package agentguard import "fmt" // BlockerCode is a stable machine-readable admission failure category. type BlockerCode string const ( BlockerCodeUnknown BlockerCode = "unknown" BlockerCodeMissingWorkspaceGrant BlockerCode = "missing_workspace_grant" BlockerCodeInvalidAdmissionRequest BlockerCode = "invalid_admission_request" BlockerCodeWorkspaceNotCanonical BlockerCode = "workspace_not_canonical" BlockerCodeWorkspaceRootEscape BlockerCode = "workspace_root_escape" BlockerCodeVCSMetadataNotAllowed BlockerCode = "vcs_metadata_not_allowed" BlockerCodeIsolationRequired BlockerCode = "isolation_required" BlockerCodeWritableRootEscape BlockerCode = "writable_root_escape" BlockerCodeWritableConfinementUnavailable BlockerCode = "writable_root_confinement_unavailable" BlockerCodeProviderUnattendedUnavailable BlockerCode = "provider_unattended_unavailable" BlockerCodeProviderApprovalBypassUnavailable BlockerCode = "provider_approval_bypass_unavailable" BlockerCodeRevisionMismatch BlockerCode = "revision_mismatch" BlockerCodePermitInvalid BlockerCode = "permit_invalid" BlockerCodePermitStale BlockerCode = "permit_stale" BlockerCodeWorkspaceIdentityMismatch BlockerCode = "workspace_identity_mismatch" ) var knownBlockerCodes = map[BlockerCode]struct{}{ BlockerCodeUnknown: {}, BlockerCodeMissingWorkspaceGrant: {}, BlockerCodeInvalidAdmissionRequest: {}, BlockerCodeWorkspaceNotCanonical: {}, BlockerCodeWorkspaceRootEscape: {}, BlockerCodeVCSMetadataNotAllowed: {}, BlockerCodeIsolationRequired: {}, BlockerCodeWritableRootEscape: {}, BlockerCodeWritableConfinementUnavailable: {}, BlockerCodeProviderUnattendedUnavailable: {}, BlockerCodeProviderApprovalBypassUnavailable: {}, BlockerCodeRevisionMismatch: {}, BlockerCodePermitInvalid: {}, BlockerCodePermitStale: {}, BlockerCodeWorkspaceIdentityMismatch: {}, } // NormalizeBlockerCode keeps future codes from being treated as a known local // policy decision. func NormalizeBlockerCode(code BlockerCode) BlockerCode { if _, ok := knownBlockerCodes[code]; ok { return code } return BlockerCodeUnknown } // Blocker is safe for task-local persistence. It carries stable identities, // never raw paths or provider diagnostics. type Blocker struct { Code BlockerCode Message string ProjectID string ProviderID string ProfileID string } func (b *Blocker) Error() string { if b == nil { return "" } if b.Message != "" { return b.Message } return fmt.Sprintf("agent admission blocked: %s", b.Code) } func blockedResult(req AdmissionRequest, code BlockerCode, message string) AdmissionResult { blocker := &Blocker{ Code: NormalizeBlockerCode(code), Message: message, ProviderID: req.Profile.ProviderID, ProfileID: req.Profile.ProfileID, } if req.Grant != nil { blocker.ProjectID = req.Grant.ProjectID } return AdmissionResult{ Status: AdmissionStatusBlocked, Blocker: blocker, Notification: notificationFor(blocker), } }