--- title: "1.35.0 — CloudFront delivery for S3 files, sites own their Permissions-Policy, one Setting row per key" description: "Private and public S3 files can now be served through CloudFront, provisioned by django-mojo under the deployment's AWS identity or brought as your own distribution, with signed links for private managers. The edge no longer sends a Permissions-Policy header; a site that wants one sets it itself. Pl…" date: "2026-10-14" tags: ["release"] canonical: "https://django-mojo.sitesmojo.com/changelog/1-35-0/" --- Private and public S3 files can now be served through CloudFront, provisioned by django-mojo under the deployment's AWS identity or brought as your own distribution, with signed links for private managers. The edge no longer sends a Permissions-Policy header; a site that wants one sets it itself. Platform-wide Setting keys are unique with a repairing migration, and a File's storage and stored object are server-controlled on REST writes. ### Breaking - The edge no longer sends `Permissions-Policy`. Camera, microphone, geolocation and media access are the site's decision; a site that relied on the platform denying them must set the header itself. - A REST create or save of a File ignores the manager, owner, stored path and name, upload token and state, link, size, checksum and category. Storage is chosen by the server: the upload rule for user sessions, and for an API key or group token only group storage its permissions allow. ### Added - CDN delivery for S3 file managers: `CdnDistribution` (one per bucket) and `CdnSigningKey` models, the `fileman_cdn` command (enable, check, byo, disable, rotate-key, revoke-key) and the FileManager actions `enable_cdn`, `check_cdn`, `disable_cdn`. - Provisioning converges additively under the deployment's AWS identity: origin access control, key group, distribution, bucket and KMS policies. A second run creates nothing; nothing is ever deleted; an untagged distribution on the same bucket is reported, never adopted. - Public managers get unsigned CDN links that never expire; private managers get signed links, default 7 days, capped by `FILEMAN_CDN_MAX_EXPIRES_IN` (default 90 days). Manager settings `cdn` (`off` opts a manager out) and `cdn_url_expires_in`. - The manager graph carries a read-only `cdn` object with the address, signed or public, and deployment status. - CloudFront invalidation when a rendition is regenerated or a file deleted; a daily job retires rotated signing keys once their links have expired. - A bring-your-own distribution can be registered and validated with exact remediation for each finding. - MojoSec per-receipt events (web probes, file-integrity changes) age out after `MOJOSEC_RECEIPT_RETENTION_DAYS`, with a count-first preview command. ### Changed - The CDN actions and settings require the global `manage_files` or `files` permission; the group-level grant that lets someone edit a manager does not drive the deployment's AWS identity. - On a CDN bucket, a private manager under a public prefix is refused, and so is a prefix containing `*` or `?`: the edge could not protect it. - Making a CDN manager private converges the edge before the save and refuses the save if CloudFront refuses. - A group manager cannot make an API key act as another member. - Short-link docs: the admin preset is not a wildcard; `manage_shortlinks` is granted by name. ### Fixed - Platform-wide Setting keys are unique; a duplicate create or a rename onto a taken key returns 400 in both scopes instead of a 500 or an arbitrary winner. - `Setting.save` with an empty `update_fields` writes and publishes nothing, and binds a positional `update_fields` the way Django does. - A nested save on a missing reverse one-to-one returns 400, not 500. - MojoSec event pruning locks each batch, so an Incident linked mid-prune keeps its Event. - testit: a refused launch never leaves an older report looking current; a raising setup function is a counted error that stops its file; a run that ran nothing fails. ### Upgrade notes - Migration `account.0055` makes platform-wide Setting keys unique. Where a key has several rows it keeps the oldest and deletes the others, logging the key and row ids (never values), and holds settings writers off while it runs. A Redis failure during its cache clear is reported and never fails the migration. - Migration `fileman.0017` adds the two CDN tables. Nothing changes for existing managers until a bucket's CDN is enabled. - CDN provisioning stores signing keys in the KMS envelope, so `KMS_KEY_ID` must be set on a deployment that enables it. A bucket on the `aws/s3` managed key is reported as manual: that key's policy cannot grant CloudFront, use a dedicated CMK. - The Permissions-Policy change applies to every edge-served page on upgrade. Sites that want the old deny behavior add the header in their own responses.