iop/packages/go/agentguard/blocker.go

88 lines
3.3 KiB
Go

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),
}
}