Skip to content
Closed
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
364 changes: 364 additions & 0 deletions proto/tea/v1/artifact.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,364 @@
// Copyright 2024-2026 CycloneDX Contributors
// SPDX-License-Identifier: Apache-2.0

syntax = "proto3";

package tea.v1;
import "buf/validate/validate.proto";

import "google/protobuf/timestamp.proto";
import "tea/v1/common.proto";

option go_package = "github.com/CycloneDX/transparency-exchange-api/gen/go/tea/v1;teav1";
option java_package = "org.cyclonedx.tea.v1";
option java_multiple_files = true;
option csharp_namespace = "CycloneDX.Tea.V1";

// ============================================================================
// TEA Artifact
// ============================================================================

// Artifact represents a TEA Artifact - a security-related document or file
// linked to a component release, such as an SBOM, VEX, attestation, or license.
//
// TEA Artifacts are strictly IMMUTABLE: if the underlying document changes,
// a new TEA Artifact object must be created. URLs referenced in this object
// must always resolve to the same resource to ensure published checksums
// remain valid and verifiable.
//
// TEA Artifacts can be reused across multiple TEA Collections, allowing the
// same document to be referenced by different component or product releases.
message Artifact {
// Unique identifier for this TEA Artifact.
// Format: UUID v4 or v7.
string uuid = 1 [
(buf.validate.field).string.uuid = true,
(buf.validate.field).required = true
];

// Human-readable name for the artifact.
string name = 2 [
(buf.validate.field).string.min_len = 1,
(buf.validate.field).string.max_len = 512
];

// Type of the artifact (SBOM, VEX, attestation, etc.).
ArtifactType type = 3 [(buf.validate.field).enum = {defined_only: true, not_in: [0]}];

// Distribution types this artifact applies to.
// If empty, the artifact applies to ALL distributions of the release.
// Values must match distributionType values from ComponentRelease.distributions.
repeated string component_distributions = 4 [json_name = "componentDistributions"];

// Available formats for this artifact.
// The same artifact content may be available in multiple formats
// (e.g., JSON and XML for CycloneDX).
repeated ArtifactFormat formats = 5 [(buf.validate.field).repeated.min_items = 1];

// Timestamp when this artifact was created in the TEA system.
google.protobuf.Timestamp created_date = 6 [json_name = "createdDate"];

// Optional description of the artifact.
string description = 7 [(buf.validate.field).string.max_len = 4096];

// Subject of the artifact (what it describes).
// For BOMs, this typically references the component/product.
ArtifactSubject subject = 8;

// Optional deprecation information.
optional Deprecation deprecation = 9;
}

// ============================================================================
// Artifact Types
// ============================================================================

// ArtifactType classifies the type of transparency artifact.
enum ArtifactType {
// Unspecified artifact type - should not be used.
ARTIFACT_TYPE_UNSPECIFIED = 0;

// Machine-readable statements containing facts, evidence, or testimony.
// Examples: in-toto attestations, SLSA provenance.
ARTIFACT_TYPE_ATTESTATION = 1;

// Bill of Materials: SBOM, OBOM, HBOM, SaaSBOM, AI/ML-BOM, etc.
// Format-agnostic (CycloneDX, SPDX, etc.).
ARTIFACT_TYPE_BOM = 2;

// Build-system specific metadata file.
// Examples: pom.xml, package.json, .nuspec, Cargo.toml.
ARTIFACT_TYPE_BUILD_META = 3;

// Industry, regulatory, or other certification from an accredited
// certification body.
ARTIFACT_TYPE_CERTIFICATION = 4;

// Describes how a component or service was manufactured or deployed.
// Includes build formulas, deployment manifests, IaC.
ARTIFACT_TYPE_FORMULATION = 5;

// License file or license information.
ARTIFACT_TYPE_LICENSE = 6;

// Release notes document.
ARTIFACT_TYPE_RELEASE_NOTES = 7;

// A security.txt file (RFC 9116).
ARTIFACT_TYPE_SECURITY_TXT = 8;

// A threat model document.
// Includes DFDs, attack trees, STRIDE analysis.
ARTIFACT_TYPE_THREAT_MODEL = 9;

// Vulnerability information: VDR (Vulnerability Disclosure Report)
// or VEX (Vulnerability Exploitability eXchange).
ARTIFACT_TYPE_VULNERABILITIES = 10;

// Common Lifecycle Enumeration document.
ARTIFACT_TYPE_CLE = 11;

// CDXA - CycloneDX Attestations.
ARTIFACT_TYPE_CDXA = 12;

// Cryptographic Bill of Materials (CBOM).
ARTIFACT_TYPE_CBOM = 13;

// Model card for ML models.
ARTIFACT_TYPE_MODEL_CARD = 14;

// Static analysis report (SARIF or proprietary).
ARTIFACT_TYPE_STATIC_ANALYSIS = 15;

// Dynamic analysis report.
ARTIFACT_TYPE_DYNAMIC_ANALYSIS = 16;

// Penetration test report.
ARTIFACT_TYPE_PENTEST_REPORT = 17;

// Risk assessment document.
ARTIFACT_TYPE_RISK_ASSESSMENT = 18;

// Plans of Action and Milestones (POAM).
ARTIFACT_TYPE_POAM = 19;

// Quality metrics report.
ARTIFACT_TYPE_QUALITY_METRICS = 20;

// Test harness or integration test suite.
ARTIFACT_TYPE_HARNESS = 21;

// Conformance test report or compliance verification.
ARTIFACT_TYPE_CONFORMANCE = 22;

// Other document type not covered above.
ARTIFACT_TYPE_OTHER = 99;
}

// ============================================================================
// Artifact Format
// ============================================================================

// ArtifactFormat represents a specific encoding/format of an artifact.
// The same artifact content may be available in multiple formats.
message ArtifactFormat {
// MIME type of the document.
// Examples:
// - application/vnd.cyclonedx+json
// - application/vnd.cyclonedx+xml
// - application/spdx+json
// - application/json
// - application/xml
// - text/plain
string mime_type = 1 [
(buf.validate.field).string.min_len = 1,
(buf.validate.field).string.max_len = 256,
json_name = "mimeType"
];

// Human-readable description of this format.
// Example: "CycloneDX SBOM (XML format)"
string description = 2 [(buf.validate.field).string.max_len = 1024];

// Direct download URL for the artifact in this format.
// Must point to an immutable resource.
string url = 3 [
(buf.validate.field).string.uri = true,
(buf.validate.field).required = true
];

// Optional URL for a detached digital signature of the artifact.
// Common formats: .asc (PGP), .sig (GPG), .p7s (PKCS#7).
string signature_url = 4 [
(buf.validate.field).string.uri = true,
(buf.validate.field).ignore = IGNORE_IF_ZERO_VALUE,
json_name = "signatureUrl"
];

// Checksums for integrity verification.
// At least SHA-256 is recommended.
repeated Checksum checksums = 5 [(buf.validate.field).repeated.min_items = 1];

// File size in bytes.
optional int64 size_bytes = 6 [json_name = "sizeBytes"];

// Encoding of the content (e.g., "utf-8", "base64").
string encoding = 7;

// Specification version (for typed artifacts).
// Example: "1.5" for CycloneDX 1.5, "2.3" for SPDX 2.3.
string spec_version = 8 [json_name = "specVersion"];
}

// ============================================================================
// Artifact Subject
// ============================================================================

// ArtifactSubject describes what entity an artifact is about.
message ArtifactSubject {
// Type of subject.
SubjectType type = 1;

// Identifiers for the subject.
repeated Identifier identifiers = 2;

// Human-readable name of the subject.
string name = 3;

// Version of the subject (if applicable).
string version = 4;
}

// SubjectType classifies what an artifact describes.
enum SubjectType {
// Unspecified subject type.
SUBJECT_TYPE_UNSPECIFIED = 0;

// The artifact describes a component.
SUBJECT_TYPE_COMPONENT = 1;

// The artifact describes a product.
SUBJECT_TYPE_PRODUCT = 2;

// The artifact describes a service.
SUBJECT_TYPE_SERVICE = 3;

// The artifact describes an organization.
SUBJECT_TYPE_ORGANIZATION = 4;

// The artifact describes a build/release process.
SUBJECT_TYPE_BUILD = 5;
}

// ============================================================================
// Artifact Content (for streaming downloads)
// ============================================================================

// ArtifactContentChunk is used for streaming artifact content.
message ArtifactContentChunk {
// Chunk of content data.
bytes data = 1;

// Offset of this chunk in the full content.
int64 offset = 2;

// Total size of the full content (in first chunk).
optional int64 total_size = 3 [json_name = "totalSize"];

// MIME type of the content (in first chunk).
string mime_type = 4 [json_name = "mimeType"];

// ETag for caching/conditional requests.
string etag = 5;
}

// ============================================================================
// Request/Response Messages
// ============================================================================

// GetArtifactRequest is the request for getting artifact metadata.
message GetArtifactRequest {
// UUID of the artifact to retrieve.
string uuid = 1 [(buf.validate.field).string.uuid = true, (buf.validate.field).required = true];
}

// GetArtifactContentRequest is the request for downloading artifact content.
message GetArtifactContentRequest {
// UUID of the artifact.
string uuid = 1 [(buf.validate.field).string.uuid = true, (buf.validate.field).required = true];

// Preferred format (MIME type). If not available, server chooses.
string preferred_format = 2 [json_name = "preferredFormat"];

// If-None-Match header for conditional requests.
// If the ETag matches, server returns NOT_MODIFIED.
string if_none_match = 3 [json_name = "ifNoneMatch"];

// Range request (for partial downloads).
// Format: "bytes=start-end"
string range = 4;
}

// GetArtifactContentResponse is the response containing artifact content.
// For large artifacts, use streaming RPC instead.
message GetArtifactContentResponse {
// Artifact content.
bytes content = 1;

// MIME type of the content.
string mime_type = 2 [json_name = "mimeType"];

// ETag for caching.
string etag = 3;

// Content length.
int64 content_length = 4 [json_name = "contentLength"];

// Last modified timestamp.
google.protobuf.Timestamp last_modified = 5 [json_name = "lastModified"];
}

// ListArtifactsRequest lists artifacts with optional filters.
message ListArtifactsRequest {
// Pagination parameters.
PageRequest pagination = 1;

// Filter by artifact type.
ArtifactType type = 2;

// Filter by MIME type.
string mime_type = 3 [json_name = "mimeType"];

// Optional sort specification.
SortSpec sort = 4;
}

// ListArtifactsResponse is the response for listing artifacts.
message ListArtifactsResponse {
// List of artifacts.
repeated Artifact artifacts = 1;

// Pagination information.
PageResponse pagination = 2;
}

// SearchArtifactsBySubjectRequest finds artifacts by their subject.
message SearchArtifactsBySubjectRequest {
// Subject identifier to search for.
Identifier identifier = 1 [(buf.validate.field).required = true];

// Filter by artifact type.
ArtifactType type = 2;

// Pagination parameters.
PageRequest pagination = 3;
}

// SearchArtifactsBySubjectResponse contains matching artifacts.
message SearchArtifactsBySubjectResponse {
// Matching artifacts.
repeated Artifact artifacts = 1;

// Pagination information.
PageResponse pagination = 2;
}
Loading