Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 0 additions & 45 deletions internal/prinfo/schemas/generate.go

This file was deleted.

71 changes: 0 additions & 71 deletions internal/schemavalidators/schemavalidators.go
Original file line numberDiff line numberDiff line change
Expand Up@@ -45,9 +45,6 @@ type AsyncAPIVersion string
// RunnerContextVersion represents the version of Runner Context schema.
type RunnerContextVersion string

// PRInfoVersion represents the version of PR/MR Info schema.
type PRInfoVersion string

// AIAgentConfigVersion represents the version of AI Agent Config schema.
type AIAgentConfigVersion string

Expand All@@ -62,14 +59,6 @@ type ScorecardVersion string
const (
// RunnerContextVersion0_1 represents Runner Context version 0.1 schema.
RunnerContextVersion0_1 RunnerContextVersion = "0.1"
// PRInfoVersion1_0 represents PR/MR Info version 1.0 schema.
PRInfoVersion1_0 PRInfoVersion = "1.0"
// PRInfoVersion1_1 represents PR/MR Info version 1.1 schema (adds reviewers).
PRInfoVersion1_1 PRInfoVersion = "1.1"
// PRInfoVersion1_2 represents PR/MR Info version 1.2 schema (adds requested and review_status to reviewers).
PRInfoVersion1_2 PRInfoVersion = "1.2"
// PRInfoVersion1_3 represents PR/MR Info version 1.3 schema (author as object with type).
PRInfoVersion1_3 PRInfoVersion = "1.3"
// CycloneDXVersion1_5 represents CycloneDX version 1.5 schema.
CycloneDXVersion1_5 CycloneDXVersion = "1.5"
// CycloneDXVersion1_6 represents CycloneDX version 1.6 schema.
Expand DownExpand Up@@ -129,16 +118,6 @@ var (
//go:embed internal_schemas/runnercontext/runner-context-response-0.1.schema.json
runnerContextSpecVersion0_1 string

// PR/MR Info schemas
//go:embed internal_schemas/prinfo/pr-info-1.0.schema.json
prInfoSpecVersion1_0 string
//go:embed internal_schemas/prinfo/pr-info-1.1.schema.json
prInfoSpecVersion1_1 string
//go:embed internal_schemas/prinfo/pr-info-1.2.schema.json
prInfoSpecVersion1_2 string
//go:embed internal_schemas/prinfo/pr-info-1.3.schema.json
prInfoSpecVersion1_3 string

// AI Agent Config schemas
//go:embed internal_schemas/aiagentconfig/ai-agent-config-0.1.schema.json
aiAgentConfigSpecVersion0_1 string
Expand DownExpand Up@@ -181,8 +160,6 @@ var (
csafOnce sync.Once
compiledRunnerContextSchemas map[RunnerContextVersion]*jsonschema.Schema
runnerContextOnce sync.Once
compiledPRInfoSchemas map[PRInfoVersion]*jsonschema.Schema
prInfoOnce sync.Once
compiledAIAgentConfigSchemas map[AIAgentConfigVersion]*jsonschema.Schema
aiAgentConfigOnce sync.Once
compiledAICodingSessionSchemas map[AICodingSessionVersion]*jsonschema.Schema
Expand DownExpand Up@@ -258,29 +235,6 @@ func initRunnerContextSchemas() {
}
}

func initPRInfoSchemas() {
compiler := jsonschema.NewCompiler()
if err := compiler.AddResource("https://schemas.chainloop.dev/prinfo/1.0/pr-info.schema.json", strings.NewReader(prInfoSpecVersion1_0)); err != nil {
panic(fmt.Sprintf("schemavalidators: failed to add resource %s: %v", "https://schemas.chainloop.dev/prinfo/1.0/pr-info.schema.json", err))
}
if err := compiler.AddResource("https://schemas.chainloop.dev/prinfo/1.1/pr-info.schema.json", strings.NewReader(prInfoSpecVersion1_1)); err != nil {
panic(fmt.Sprintf("schemavalidators: failed to add resource %s: %v", "https://schemas.chainloop.dev/prinfo/1.1/pr-info.schema.json", err))
}
if err := compiler.AddResource("https://schemas.chainloop.dev/prinfo/1.2/pr-info.schema.json", strings.NewReader(prInfoSpecVersion1_2)); err != nil {
panic(fmt.Sprintf("schemavalidators: failed to add resource %s: %v", "https://schemas.chainloop.dev/prinfo/1.2/pr-info.schema.json", err))
}
if err := compiler.AddResource("https://schemas.chainloop.dev/prinfo/1.3/pr-info.schema.json", strings.NewReader(prInfoSpecVersion1_3)); err != nil {
panic(fmt.Sprintf("schemavalidators: failed to add resource %s: %v", "https://schemas.chainloop.dev/prinfo/1.3/pr-info.schema.json", err))
}

compiledPRInfoSchemas = map[PRInfoVersion]*jsonschema.Schema{
PRInfoVersion1_0: compiler.MustCompile("https://schemas.chainloop.dev/prinfo/1.0/pr-info.schema.json"),
PRInfoVersion1_1: compiler.MustCompile("https://schemas.chainloop.dev/prinfo/1.1/pr-info.schema.json"),
PRInfoVersion1_2: compiler.MustCompile("https://schemas.chainloop.dev/prinfo/1.2/pr-info.schema.json"),
PRInfoVersion1_3: compiler.MustCompile("https://schemas.chainloop.dev/prinfo/1.3/pr-info.schema.json"),
}
}

func initAIAgentConfigSchemas() {
compiler := jsonschema.NewCompiler()
if err := compiler.AddResource("https://schemas.chainloop.dev/aiagentconfig/0.1/ai-agent-config.schema.json", strings.NewReader(aiAgentConfigSpecVersion0_1)); err != nil {
Expand DownExpand Up@@ -415,31 +369,6 @@ func ValidateChainloopRunnerContext(data interface{}, version RunnerContextVersi
return nil
}

// ValidatePRInfo validates the PR/MR info schema.
func ValidatePRInfo(data interface{}, version PRInfoVersion) error {
prInfoOnce.Do(initPRInfoSchemas)

if version == "" {
version = PRInfoVersion1_3
}

schema, ok := compiledPRInfoSchemas[version]
if !ok {
return errors.New("invalid PR info schema version")
}

if err := schema.Validate(data); err != nil {
var invalidJSONTypeError jsonschema.InvalidJSONTypeError
if errors.As(err, &invalidJSONTypeError) {
return ErrInvalidJSONPayload
}
return err
}

return nil
}

// ValidateAIAgentConfig validates the AI agent config schema.
func ValidateAIAgentConfig(data any, version AIAgentConfigVersion) error {
aiAgentConfigOnce.Do(initAIAgentConfigSchemas)

Expand Down
41 changes: 0 additions & 41 deletions internal/schemavalidators/schemavalidators_test.go
Original file line numberDiff line numberDiff line change
Expand Up@@ -235,47 +235,6 @@ func TestValidateRunnerContext(t *testing.T) {
}
}

func TestValidatePRInfo(t *testing.T) {
testCases := []struct {
name string
filePath string
wantErr string
}{
{
name: "valid PR info with all fields",
filePath: "./testdata/pr_info_valid.json",
},
{
name: "missing required fields",
filePath: "./testdata/pr_info_missing_required.json",
wantErr: "missing properties",
},
{
name: "completely wrong format",
filePath: "./testdata/sbom-spdx.json",
wantErr: "missing properties",
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
f, err := os.ReadFile(tc.filePath)
require.NoError(t, err)

var v any
require.NoError(t, json.Unmarshal(f, &v))

err = schemavalidators.ValidatePRInfo(v, "")
if tc.wantErr != "" {
require.ErrorContains(t, err, tc.wantErr)
return
}

require.NoError(t, err)
})
}
}

func TestValidateAICodingSession(t *testing.T) {
testCases := []struct {
name string
Expand Down
2 changes: 1 addition & 1 deletion pkg/attestation/crafter/collector_prmetadata.go
Original file line numberDiff line numberDiff line change
Expand Up@@ -22,8 +22,8 @@ import (
"os"

schemaapi "github.com/chainloop-dev/chainloop/app/controlplane/api/workflowcontract/v1"
"github.com/chainloop-dev/chainloop/internal/prinfo"
"github.com/chainloop-dev/chainloop/pkg/casclient"
"github.com/chainloop-dev/chainloop/pkg/prinfo"
)

// PRMetadataCollector collects pull/merge request metadata from the CI environment.
Expand Down
5 changes: 2 additions & 3 deletions pkg/attestation/crafter/materials/chainloop_pr_info.go
Original file line numberDiff line numberDiff line change
Expand Up@@ -22,10 +22,9 @@ import (
"os"

schemaapi "github.com/chainloop-dev/chainloop/app/controlplane/api/workflowcontract/v1"
"github.com/chainloop-dev/chainloop/internal/prinfo"
"github.com/chainloop-dev/chainloop/internal/schemavalidators"
api "github.com/chainloop-dev/chainloop/pkg/attestation/crafter/api/attestation/v1"
"github.com/chainloop-dev/chainloop/pkg/casclient"
"github.com/chainloop-dev/chainloop/pkg/prinfo"

"github.com/rs/zerolog"
)
Expand DownExpand Up@@ -75,7 +74,7 @@ func (i *ChainloopPRInfoCrafter) Craft(ctx context.Context, artifactPath string)
}

// Validate the data against JSON schema
if err := schemavalidators.ValidatePRInfo(rawData, schemavalidators.PRInfoVersion1_3); err != nil {
if err := prinfo.Validate(rawData, prinfo.LatestVersion); err != nil {
i.logger.Debug().Err(err).Msg("schema validation failed")
return nil, fmt.Errorf("PR info validation failed: %w", err)
}
Expand Down
9 changes: 4 additions & 5 deletions pkg/attestation/crafter/materials/chainloop_pr_info_test.go
Original file line numberDiff line numberDiff line change
Expand Up@@ -22,8 +22,7 @@ import (
"testing"

schemaapi "github.com/chainloop-dev/chainloop/app/controlplane/api/workflowcontract/v1"
"github.com/chainloop-dev/chainloop/internal/prinfo"
"github.com/chainloop-dev/chainloop/internal/schemavalidators"
"github.com/chainloop-dev/chainloop/pkg/prinfo"
"github.com/rs/zerolog"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
Expand DownExpand Up@@ -118,7 +117,7 @@ func TestChainloopPRInfoCrafter_Validation(t *testing.T) {
require.NoError(t, err)

// Validate the data against JSON schema
err = schemavalidators.ValidatePRInfo(rawData, schemavalidators.PRInfoVersion1_3)
err = prinfo.Validate(rawData, prinfo.LatestVersion)

if tc.wantErr {
require.Error(t, err)
Expand All@@ -143,7 +142,7 @@ func TestChainloopPRInfoCrafter_BackwardCompat(t *testing.T) {
err := json.Unmarshal([]byte(oldFormatJSON), &rawData)
require.NoError(t, err)

err = schemavalidators.ValidatePRInfo(rawData, schemavalidators.PRInfoVersion1_3)
err = prinfo.Validate(rawData, prinfo.LatestVersion)
require.NoError(t, err)

// New object author format should also validate against v1.3
Expand All@@ -158,7 +157,7 @@ func TestChainloopPRInfoCrafter_BackwardCompat(t *testing.T) {
err = json.Unmarshal([]byte(newFormatJSON), &rawData)
require.NoError(t, err)

err = schemavalidators.ValidatePRInfo(rawData, schemavalidators.PRInfoVersion1_3)
err = prinfo.Validate(rawData, prinfo.LatestVersion)
require.NoError(t, err)
}

Expand Down
2 changes: 1 addition & 1 deletion pkg/attestation/crafter/prmetadata.go
Original file line numberDiff line numberDiff line change
Expand Up@@ -26,7 +26,7 @@ import (
"time"

schemaapi "github.com/chainloop-dev/chainloop/app/controlplane/api/workflowcontract/v1"
"github.com/chainloop-dev/chainloop/internal/prinfo"
"github.com/chainloop-dev/chainloop/pkg/prinfo"
)

// PRMetadata holds extracted PR/MR information
Expand Down
2 changes: 1 addition & 1 deletion pkg/attestation/crafter/prmetadata_test.go
Original file line numberDiff line numberDiff line change
Expand Up@@ -24,7 +24,7 @@ import (
"path/filepath"
"testing"

"github.com/chainloop-dev/chainloop/internal/prinfo"
"github.com/chainloop-dev/chainloop/pkg/prinfo"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
Expand Down
10 changes: 5 additions & 5 deletions internal/prinfo/generator.go → pkg/prinfo/generator.go
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
//
// Copyright 2025 The Chainloop Authors.
// Copyright 2025-2026 The Chainloop Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand DownExpand Up@@ -32,8 +32,8 @@ func NewGenerator() *Generator {
return &Generator{}
}

// GeneratePRInfoSchema generates a JSON schema for the PR/MR info data.
func (g *Generator) GeneratePRInfoSchema(version string) *jsonschema.Schema {
// GenerateSchema generates a JSON schema for the PR/MR info data.
func (g *Generator) GenerateSchema(version Version) *jsonschema.Schema {
r := &jsonschema.Reflector{
DoNotReference: true,
ExpandedStruct: true,
Expand All@@ -44,7 +44,7 @@ func (g *Generator) GeneratePRInfoSchema(version string) *jsonschema.Schema {

schema := r.Reflect(&Data{})

schema.ID = jsonschema.ID(fmt.Sprintf("https://schemas.chainloop.dev/prinfo/%s/pr-info.schema.json", version))
schema.ID = jsonschema.ID(SchemaURL(version))
schema.Title = "Pull Request / Merge Request Information"
schema.Description = "Schema for Pull Request or Merge Request metadata collected during attestation"
// we want to have a specific version of the schema to avoid compatibility issues
Expand All@@ -54,7 +54,7 @@ func (g *Generator) GeneratePRInfoSchema(version string) *jsonschema.Schema {
}

// Save writes the schema to a file
func (g *Generator) Save(schema *jsonschema.Schema, outputDir, version string) error {
func (g *Generator) Save(schema *jsonschema.Schema, outputDir string, version Version) error {
schemaJSON, err := json.MarshalIndent(schema, "", " ")
if err != nil {
return fmt.Errorf("failed to marshal schema to JSON: %w", err)
Expand Down
File renamed without changes.
10 changes: 4 additions & 6 deletions internal/prinfo/prinfo_test.go → pkg/prinfo/prinfo_test.go
Original file line numberDiff line numberDiff line change
Expand Up@@ -19,8 +19,6 @@ import (
"encoding/json"
"testing"

"github.com/chainloop-dev/chainloop/internal/schemavalidators"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
Expand DownExpand Up@@ -175,7 +173,7 @@ func TestValidatePRInfo(t *testing.T) {
require.NoError(t, err)
}

err = schemavalidators.ValidatePRInfo(data, schemavalidators.PRInfoVersion1_1)
err = Validate(data, Version1_1)
if tc.wantErr {
assert.Error(t, err)
} else {
Expand DownExpand Up@@ -253,7 +251,7 @@ func TestValidatePRInfoV1_2(t *testing.T) {
err := json.Unmarshal([]byte(tc.data), &data)
require.NoError(t, err)

err = schemavalidators.ValidatePRInfo(data, schemavalidators.PRInfoVersion1_2)
err = Validate(data, Version1_2)
if tc.wantErr {
assert.Error(t, err)
} else {
Expand DownExpand Up@@ -299,7 +297,7 @@ func TestValidatePRInfoV1_0BackwardCompat(t *testing.T) {
err := json.Unmarshal([]byte(tc.data), &data)
require.NoError(t, err)

err = schemavalidators.ValidatePRInfo(data, schemavalidators.PRInfoVersion1_0)
err = Validate(data, Version1_0)
if tc.wantErr {
assert.Error(t, err)
} else {
Expand DownExpand Up@@ -429,7 +427,7 @@ func TestValidatePRInfoV1_3(t *testing.T) {
err := json.Unmarshal([]byte(tc.data), &data)
require.NoError(t, err)

err = schemavalidators.ValidatePRInfo(data, schemavalidators.PRInfoVersion1_3)
err = Validate(data, Version1_3)
if tc.wantErr {
assert.Error(t, err)
} else {
Expand Down
Loading
Loading