What the SDK does on first use
Before it writes a byte, the store checks the bucket once. There are two acceptable outcomes and a third the check exists to prevent.unknown is not off. A credential missing s3:GetObjectLockConfiguration,
or a 403 on HeadBucket, means the SDK cannot see the protection rather than
that there is none. A guard that stands down where it cannot look guards
nothing.
Object Lock enabled is not the same as protected. With no default retention
rule, objects in a lock-enabled bucket carry no retention and delete like any
other, so that state is reported as unprotected, because it is. Setting
days: 0 is a legitimate choice for a customer applying per-object retention
themselves, and the readiness check says what it sees.
warn is the default and it is not a silent third outcome: the write goes
ahead and is announced with the property named. refuse is the posture for a
customer who would rather hold no evidence than hold evidence they cannot
defend.The three credentials
Three roles, three policies. ReplaceBUCKET throughout.
Provisioner, one time, not the agent
Creates the bucket with its protection. A human or a CI job runs this once and the agent never holds it.s3:CreateBucket is the permission that makes an
unprotected-bucket mistake permanent, so it does not belong in a long-lived
agent credential.
createBucket: false when a platform team or Terraform provisions the
bucket instead. The protection check still runs: turning off creation does
not turn off the reporting.
Writer, the agent
Adds objects. It cannot read them back, cannot list them, cannot delete anything, and cannot create or reconfigure a bucket.Reader, the pack-runner
Reads objects and nothing else. No write, no delete, no configuration. This is the credential that syncs the bucket down before you build a pack.s3:DeleteObject. Nothing in this system
deletes evidence, so nothing that touches the bucket is granted the ability to.
Object Lock is the backstop for a credential that gets one anyway.
Backends
Do not take this table as settled for your deployment. The SDK detects and
reports, which is the only claim that survives a backend changing under you.
Verify against a real bucket before you rely on it.
Check without gating
checkProtection() in TypeScript, check_protection() in Python, returns
the verdict and writes nothing. It names no bucket
and no key, so it is safe to surface somewhere that must stay content-blind:
a health endpoint, a readiness probe, a dashboard tile.