Skip to content

Commit 1a3ea39

Browse files
waveywavesclaude
andcommitted
fix(crafter): use deterministic filename for AI config collector
Replace os.CreateTemp (which generates a random suffix) with a deterministic filename derived from the config's content hash (ConfigHash[:12]). This ensures that retries produce the same temp file path, preventing duplicate CAS uploads when the attestation is retried due to remote state conflicts. Fixes: #2907 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Vibhav Bobade <vibhav.bobde@gmail.com>
1 parent 232fff0 commit 1a3ea39

1 file changed

Lines changed: 7 additions & 10 deletions

File tree

pkg/attestation/crafter/collector_aiagentconfig.go

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"encoding/json"
2121
"fmt"
2222
"os"
23+
"path/filepath"
2324
"sort"
2425

2526
schemaapi "github.com/chainloop-dev/chainloop/app/controlplane/api/workflowcontract/v1"
@@ -99,20 +100,16 @@ func (c *AIAgentConfigCollector) uploadAgentConfig(
99100
return fmt.Errorf("marshaling AI agent config for %s: %w", agentName, err)
100101
}
101102

102-
tmpFile, err := os.CreateTemp("", fmt.Sprintf("ai-agent-config-%s-*.json", agentName))
103-
if err != nil {
104-
return fmt.Errorf("creating temp file: %w", err)
105-
}
106-
defer os.Remove(tmpFile.Name())
107-
108-
if _, err := tmpFile.Write(jsonData); err != nil {
109-
tmpFile.Close()
103+
// Use a deterministic filename based on the config hash so that retries
104+
// produce the same file path and avoid duplicate CAS uploads.
105+
tmpPath := filepath.Join(os.TempDir(), fmt.Sprintf("ai-agent-config-%s-%s.json", agentName, data.ConfigHash[:12]))
106+
if err := os.WriteFile(tmpPath, jsonData, 0o600); err != nil {
110107
return fmt.Errorf("writing temp file: %w", err)
111108
}
112-
tmpFile.Close()
109+
defer os.Remove(tmpPath)
113110

114111
materialName := fmt.Sprintf("ai-agent-config-%s", agentName)
115-
if _, err := cr.AddMaterialContractFree(ctx, attestationID, schemaapi.CraftingSchema_Material_CHAINLOOP_AI_AGENT_CONFIG.String(), materialName, tmpFile.Name(), casBackend, nil); err != nil {
112+
if _, err := cr.AddMaterialContractFree(ctx, attestationID, schemaapi.CraftingSchema_Material_CHAINLOOP_AI_AGENT_CONFIG.String(), materialName, tmpPath, casBackend, nil); err != nil {
116113
return fmt.Errorf("adding AI agent config material for %s: %w", agentName, err)
117114
}
118115

0 commit comments

Comments
 (0)