Skip to content

Evidence attachments#40

Merged
mnsboev merged 4 commits intomainfrom
evidence_attachments
Mar 19, 2026
Merged

Evidence attachments#40
mnsboev merged 4 commits intomainfrom
evidence_attachments

Conversation

@mnsboev
Copy link
Copy Markdown
Collaborator

@mnsboev mnsboev commented Mar 16, 2026

Add External Attachment Support to jf evd create

Summary

This PR adds file attachment support to jf evd create, allowing users to attach supplementary files (reports, SBOMs, scan results) to in-toto evidence. Two attachment modes are supported:

  • --attach-local — attach a local file (uploaded temporarily to Artifactory, then auto-cleaned after creation)
  • --attach-artifactory-path — reference a file already in Artifactory

How It Works

Attachment Flow

┌─────────────────────────────────────────────────────────────┐
│                    jf evd create                            │
│                                                             │
│  --attach-local /path/to/report.pdf                         │
│  --attach-artifactory-temp-path my-repo/tmp/                │
│                                                             │
│  1. Upload local file → my-repo/tmp/report.pdf              │
│  2. Fetch file info (sha256, metadata)                      │
│  3. Embed attachment metadata in DSSE statement             │
│  4. Wrap DSSE + attachment location in upload request       │
│  5. Send to Evidence service                                │
│  6. Delete temporary file from Artifactory  ← auto-cleanup  │
└─────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────┐
│                    jf evd create                            │
│                                                             │
│  --attach-artifactory-path my-repo/reports/scan.json        │
│                                                             │
│  1. Fetch file info (sha256, metadata)                      │
│  2. Embed attachment metadata in DSSE statement             │
│  3. Wrap DSSE + attachment location in upload request       │
│  4. Send to Evidence service                                │
│  (no upload, no cleanup — file stays in place)              │
└─────────────────────────────────────────────────────────────┘

Temporary File Lifecycle (local attachments)

When using --attach-local, the local file is uploaded to a temporary Artifactory path, its SHA-256 checksum is resolved, attachment metadata is embedded into the DSSE envelope, and the upload request is sent to the Evidence service. After the evidence is created, the temporary file is automatically deleted from Artifactory. The file only exists in Artifactory for the duration of the create operation.

Backward Compatibility

The upload request to the Evidence service includes attachment metadata (repository, path, sha256) only when attachments are present. The jfrog-client-go layer performs a version check before sending attachment data — if the Evidence service version is below 7.646.1 and artifactory 7.143.0, the request is rejected client-side with a clear error message. Requests without attachments are unaffected.

--attach-artifactory-temp-path Persistence

The --attach-artifactory-temp-path value is resolved from multiple sources in order:

  1. CLI flag --attach-artifactory-temp-path
  2. Environment variable EVIDENCE_ATTACHMENT_ARTIFACTORY_TEMP_PATH
  3. Config file .jfrog/evidence/evidence.yml key attachment.artifactoryTempPath

Once provided, the value is automatically persisted to the config file for subsequent runs. This means --attach-artifactory-temp-path only needs to be specified once.

Validation Rules

Condition Result
--attach-local + --attach-artifactory-path Error: mutually exclusive
--attach-artifactory-temp-path without --attach-local Error: temp path only valid with local attachments
--attach-local without --attach-artifactory-temp-path (and no persisted/env value) Error with guidance to set flag, env var, or config key
Attachments with --sigstore-bundle Error: attachments only supported in in-toto flow

CLI Examples

1. Local file attachment

jf evd create \
  --subject-repo-path "my-repo/builds/artifact-v1.2.3.tar.gz" \
  --predicate '{"build":"123","source":"ci"}' \
  --predicate-type "https://slsa.dev/provenance/v1" \
  --key "/path/to/private.key" \
  --key-alias "signing-key" \
  --attach-local "/path/to/scan-report.json" \
  --attach-artifactory-temp-path "my-repo/tmp/"

On subsequent runs, --attach-artifactory-temp-path can be omitted — the value is persisted:

jf evd create \
  --subject-repo-path "my-repo/builds/artifact-v1.2.4.tar.gz" \
  --predicate '{"build":"124"}' \
  --predicate-type "https://slsa.dev/provenance/v1" \
  --key "/path/to/private.key" \
  --key-alias "signing-key" \
  --attach-local "/path/to/scan-report.json"

2. Existing Artifactory file attachment

jf evd create \
  --subject-repo-path "my-repo/builds/artifact-v1.2.3.tar.gz" \
  --predicate '{"build":"123","source":"ci"}' \
  --predicate-type "https://slsa.dev/provenance/v1" \
  --key "/path/to/private.key" \
  --key-alias "signing-key" \
  --attach-artifactory-path "my-repo/reports/security-scan.json"

What Changed

jfrog-cli-evidence

  • New flags: --attach-local, --attach-artifactory-path, --attach-artifactory-temp-path
  • Attachment resolution, upload, MIME detection, and auto-cleanup logic in evidence/create/attachments.go
  • DSSE payload construction with attachment metadata in the statement
  • Upload request wrapping with attachment location (repository, path, sha256) for server-side handling
  • Config persistence for --attach-artifactory-temp-path via env var, config file, or flag
  • Validation ensuring mutual exclusivity and correct flag combinations

jfrog-client-go

PR: jfrog/jfrog-client-go#1325

  • EvidenceDetails extended with Attachments []AttachmentDetails field
  • Version-gated compatibility check: attachment requests are rejected client-side if Evidence service version < 7.646.1

Testing

  • Tests added/updated
  • All tests pass locally

Checklist

  • PR description is clear and concise, and it includes the proposed solution/fix
  • Code follows project style guidelines
  • Documentation updated (if applicable)

Comment thread tests/e2e/local/.env Outdated
@alenon
Copy link
Copy Markdown
Collaborator

alenon commented Mar 18, 2026

validateAttachmentFlags catches an error from PersistAttachmentTempTarget but then returns nil, silently treating a config persistence failure as success. The error is also logged with %w which log.Warn doesn't support (it's variadic, not a format function), so the actual error message will be garbled.

if attachLocal != "" && ctx.IsFlagSet(flags.AttachTempTarget) {
if err := evdConfig.PersistAttachmentTempTarget(ctx.GetStringFlagValue(flags.AttachTempTarget)); err != nil {
log.Warn("error persisting attachment temp target: %w", err)
return nil
}
}
return nil
}

Comment thread evidence/cli/command/command_cli.go Outdated
Comment thread evidence/cli/command/flags/command_flags.go Outdated
Comment thread evidence/cli/command/flags/command_flags.go Outdated
@mnsboev mnsboev merged commit df2610d into main Mar 19, 2026
16 of 17 checks passed
@mnsboev mnsboev deleted the evidence_attachments branch March 19, 2026 12:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature New feature or functionality

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants