S3 Versioned Artifact Ingress
AppTheoryS3VersionedIngress is the single bucket contract for Theory Cloud namespace release bundles. It creates one
S3 bucket with versioning enabled so vetting, registration, and deployment can bind to the same immutable
(key, version ID, digest) tuple. The object layout is fixed:
ns/<namespaceSlug>/<bundleId>
AppTheoryS3VersionedIngress.KEY_ROOT and the instance keyRoot accessor both expose the canonical ns/ root.
Consumers must not duplicate that literal or add another upload layout.
const ingress = new AppTheoryS3VersionedIngress(this, "ArtifactIngress", {
bucketName: "theorycloud-artifact-ingress",
});
ingress.grantUpload(uploadRole, "acme", "rel_0123456789abcdefghijklmnop");
ingress.grantVersionedRead(vettingRole, "acme", "rel_0123456789abcdefghijklmnop");
The bucketName prop is optional and changes only the physical bucket name. bucketName and bucketArn accessors
forward the created bucket’s CloudFormation tokens; they do not expose a second bucket or grant path.
Fixed bucket posture
The construct always emits:
- S3 versioning with status
Enabled - all four S3 public-access-block settings
- S3-managed server-side encryption (
AES256), matching AppTheory’s existing bucket default - bucket-owner-enforced object ownership
- a bucket policy denying non-TLS access through
aws:SecureTransport - an enabled lifecycle rule that aborts incomplete multipart uploads after 7 days
- CloudFormation retain semantics on deletion and replacement
The construct intentionally emits no object-expiration or noncurrent-version-deletion rule. Namespace deployment requires pinned versions to remain readable, and the accepted artifact-flow contract does not define a quarantine retention period. Changing the incomplete-upload reaping window is a contract change, not a caller- or operator-supplied override.
Exact-key grants
grantUpload(grantee, namespaceSlug, bundleId) returns an IAM grant containing exactly one action, s3:PutObject, and
grantVersionedRead(...) returns a separate grant containing exactly one action, s3:GetObjectVersion. For literal
inputs, each grant targets exactly one bundle object ARN and grants neither bucket listing nor unversioned reads.
s3:PutObject inherently authorizes CreateMultipartUpload, UploadPart, and CompleteMultipartUpload on that same
key; the helper does not grant the separate s3:AbortMultipartUpload or s3:ListMultipartUploadParts actions. The
bucket’s enabled lifecycle rule aborts incomplete multipart uploads after 7 days, so the omitted abort grant leaves no
permanent incomplete-upload residue.
Literal namespace slugs must match ^[a-z0-9][a-z0-9-]{1,62}$. Literal bundle IDs must match
^rel_[0-9a-z]{26}$. Invalid literals fail synthesis instead of being trimmed, lowercased, or broadened.
CloudFormation token values follow AppTheory’s accepted Option A token-policy convention: structural inputs remain
required, while Token.isUnresolved skips literal value validation. Literal inputs therefore remain exact and
wildcard-free. CloudFormation resolves token values at deployment; AppTheory cannot guarantee exactness for
token-valued inputs. The object resource remains a CloudFormation-safe join of the bucket ARN, ns/, namespace token,
slash, and bundle token.
Authority boundary
This construct owns bucket shape and IAM grant scoping only. It does not mint ULIDs, define theorycloud:// artifact
URIs, issue STS credentials or presigned requests, validate uploaded bytes, or deploy the bucket into
platform_control. An operator-authorized platform stack decides when to provision it; namespace application stacks
and upload tooling consume the resulting identity and least-privilege grant contract.