package main import ( "fmt" "os" "git.cin.su/m/Assistant/contracts/capability" "git.cin.su/m/Assistant/contracts/identity" ) // candidateReleaseContextFromRuntime accepts only deployment-owned metadata. // It never derives a candidate slot from an HTTP request or notification body. func candidateReleaseContextFromRuntime() (*capability.CandidateReleaseContext, error) { const prefix = "CANDIDATE_" release := os.Getenv(prefix + "RELEASE_SET_ID") if release == "" { return nil, nil } context := &capability.CandidateReleaseContext{ ReleaseSetID: release, Slot: os.Getenv(prefix + "SLOT"), TaskID: os.Getenv(prefix + "TASK_ID"), PrincipalID: identity.PrincipalID(os.Getenv(prefix + "PRINCIPAL_ID")), CapabilityID: capability.CapabilityID(os.Getenv(prefix + "CAPABILITY_ID")), ResourceScope: os.Getenv(prefix + "RESOURCE_SCOPE"), Mode: capability.CandidateBindingMode(os.Getenv(prefix + "BINDING_MODE")), TargetKind: os.Getenv(prefix + "TARGET_KIND"), TargetRef: os.Getenv(prefix + "TARGET_REF"), TargetDigest: os.Getenv(prefix + "TARGET_DIGEST"), AuthorityGrantID: os.Getenv(prefix + "AUTHORITY_GRANT_ID"), } var revision int64 if _, err := fmt.Sscan(os.Getenv(prefix+"TASK_REVISION"), &revision); err != nil { return nil, fmt.Errorf("candidate task revision: %w", err) } context.TaskRevision = revision if context.Slot == "" || context.TaskID == "" || context.TaskRevision < 1 || context.PrincipalID == "" || context.CapabilityID == "" || context.ResourceScope == "" || context.Mode == "" || context.TargetKind == "" || context.TargetRef == "" || context.TargetDigest == "" || context.AuthorityGrantID == "" { return nil, fmt.Errorf("incomplete candidate release metadata") } return context, nil }