62 lines
3.1 KiB
Go
62 lines
3.1 KiB
Go
package cisupplychainconformance
|
|||
|
|
|
||
|
|
import (
|
||
|
|
"strings"
|
||
|
|
"testing"
|
||
|
|
"time"
|
||
|
|
)
|
||
|
|
|
||
|
|
func TestRemoteManagedCICompleteEvidencePasses(t *testing.T) {
|
||
|
|
t.Parallel()
|
||
|
|
capture := ciFixture("REMOTE_MANAGED_CI")
|
||
|
|
report := Evaluate(capture, capture.CandidateVersion, capture.BuildDigest, capture.SourceCommit, time.Now())
|
||
|
|
if report.Result != "PASS" || report.EvidenceScope != "REMOTE_CI_SUPPLY_CHAIN" || report.ExternalValidationRequired || len(report.CompletedChecks) != len(RequiredChecks) {
|
||
|
|
t.Fatalf("unexpected report: %+v", report)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestMissingRequiredArtifactFails(t *testing.T) {
|
||
|
|
t.Parallel()
|
||
|
|
capture := ciFixture("REMOTE_MANAGED_CI")
|
||
|
|
capture.SBOMs = capture.SBOMs[:2]
|
||
|
|
report := Evaluate(capture, capture.CandidateVersion, capture.BuildDigest, capture.SourceCommit, time.Now())
|
||
|
|
if report.Result != "FAIL" || !report.ExternalValidationRequired {
|
||
|
|
t.Fatalf("expected failed report: %+v", report)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestLocalToolchainCannotCompleteExternalValidation(t *testing.T) {
|
||
|
|
t.Parallel()
|
||
|
|
capture := ciFixture("LOCAL_TOOLCHAIN")
|
||
|
|
capture.Provider = "LOCAL_GO_TEST"
|
||
|
|
report := Evaluate(capture, capture.CandidateVersion, capture.BuildDigest, capture.SourceCommit, time.Now())
|
||
|
|
if report.Result != "PASS" || report.EvidenceScope != "LOCAL_CI_TOOLCHAIN" || !report.ExternalValidationRequired {
|
||
|
|
t.Fatalf("unexpected local report: %+v", report)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func ciFixture(source string) Capture {
|
||
|
|
started := time.Date(2026, 8, 25, 9, 0, 0, 0, time.UTC)
|
||
|
|
digest := "sha256:" + strings.Repeat("a", 64)
|
||
|
|
checks := make([]CheckResult, 0, len(RequiredChecks))
|
||
|
|
for _, code := range RequiredChecks {
|
||
|
|
checks = append(checks, CheckResult{Code: code, Status: "PASS", EvidenceRef: "artifact:checks/" + strings.ToLower(code)})
|
||
|
|
}
|
||
|
|
images := make([]ImageArtifact, 0, len(RequiredImages))
|
||
|
|
for position, subject := range RequiredImages {
|
||
|
|
images = append(images, ImageArtifact{Subject: subject, Reference: "registry.example.com/voice/" + strings.ToLower(subject), Digest: "sha256:" + strings.Repeat(string(rune('b'+position)), 64), EvidenceRef: "artifact:images/" + strings.ToLower(subject)})
|
||
|
|
}
|
||
|
|
sboms := make([]SBOMArtifact, 0, len(RequiredSBOMs))
|
||
|
|
for position, subject := range RequiredSBOMs {
|
||
|
|
sboms = append(sboms, SBOMArtifact{Subject: subject, Format: "CYCLONEDX_JSON", Digest: "sha256:" + strings.Repeat(string(rune('d'+position)), 64), EvidenceRef: "artifact:sbom/" + strings.ToLower(subject)})
|
||
|
|
}
|
||
|
|
return Capture{
|
||
|
|
SchemaVersion: CaptureSchema, EvidenceSource: source, CandidateVersion: "0.64.0-rc.1", BuildDigest: digest,
|
||
|
|
SourceCommit: strings.Repeat("1", 40), Provider: "GITHUB_ACTIONS", RepositoryRef: "github:example/voice-platform",
|
||
|
|
WorkflowRef: ".github/workflows/ci.yml@refs/tags/v0.64.0-rc.1", RunID: "123456789", RunURL: "https://github.com/example/voice-platform/actions/runs/123456789",
|
||
|
|
Trigger: "RELEASE", Ref: "refs/tags/v0.64.0-rc.1", Attempt: 1, Conclusion: "SUCCESS", StartedAt: started, CompletedAt: started.Add(20 * time.Minute),
|
||
|
|
CollectedAt: started.Add(25 * time.Minute), ExecutedByRef: "release-engineer", ReviewedByRef: "security-reviewer", ReviewRef: "approval:SEC-2026-081",
|
||
|
|
Checks: checks, Images: images, SBOMs: sboms,
|
||
|
|
}
|
||
|
|
}
|