diff --git a/.github/workflows/build_external_container_images.yaml b/.github/workflows/build_external_container_images.yaml index 7876dbfcb..8c90f59bf 100644 --- a/.github/workflows/build_external_container_images.yaml +++ b/.github/workflows/build_external_container_images.yaml @@ -5,12 +5,14 @@ on: permissions: contents: read - packages: write jobs: build_and_push_images: name: Build and Push ${{ matrix.image.name }} Image runs-on: ubuntu-latest + permissions: + contents: read + packages: write strategy: matrix: image: diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 56950d13f..fec86ea7c 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -11,7 +11,6 @@ on: permissions: contents: read - id-token: write # required for SLSA attestation jobs: analyze: diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index b28cd78ff..2e20ae0e4 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -5,6 +5,8 @@ on: - cron: '30 1 * * *' workflow_dispatch: +permissions: {} + jobs: close-issues: runs-on: ubuntu-latest diff --git a/pkg/attestation/crafter/collector_aiagentconfig.go b/pkg/attestation/crafter/collector_aiagentconfig.go index 4b67f97e6..901513fcb 100644 --- a/pkg/attestation/crafter/collector_aiagentconfig.go +++ b/pkg/attestation/crafter/collector_aiagentconfig.go @@ -20,6 +20,7 @@ import ( "encoding/json" "fmt" "os" + "path/filepath" "sort" schemaapi "github.com/chainloop-dev/chainloop/app/controlplane/api/workflowcontract/v1" @@ -99,20 +100,16 @@ func (c *AIAgentConfigCollector) uploadAgentConfig( return fmt.Errorf("marshaling AI agent config for %s: %w", agentName, err) } - tmpFile, err := os.CreateTemp("", fmt.Sprintf("ai-agent-config-%s-*.json", agentName)) - if err != nil { - return fmt.Errorf("creating temp file: %w", err) - } - defer os.Remove(tmpFile.Name()) - - if _, err := tmpFile.Write(jsonData); err != nil { - tmpFile.Close() + // Use a deterministic filename based on the config hash so that retries + // produce the same file path and avoid duplicate CAS uploads. + tmpPath := filepath.Join(os.TempDir(), fmt.Sprintf("ai-agent-config-%s-%s.json", agentName, data.ConfigHash[:12])) + if err := os.WriteFile(tmpPath, jsonData, 0o600); err != nil { return fmt.Errorf("writing temp file: %w", err) } - tmpFile.Close() + defer os.Remove(tmpPath) materialName := fmt.Sprintf("ai-agent-config-%s", agentName) - if _, err := cr.AddMaterialContractFree(ctx, attestationID, schemaapi.CraftingSchema_Material_CHAINLOOP_AI_AGENT_CONFIG.String(), materialName, tmpFile.Name(), casBackend, nil); err != nil { + if _, err := cr.AddMaterialContractFree(ctx, attestationID, schemaapi.CraftingSchema_Material_CHAINLOOP_AI_AGENT_CONFIG.String(), materialName, tmpPath, casBackend, nil); err != nil { return fmt.Errorf("adding AI agent config material for %s: %w", agentName, err) }