| """WHICH STORE THIS DEPLOYMENT IS ALLOWED TO WRITE β the fail-closed binding (D-315 / D-298). |
| |
| ββ THE SENTENCE THIS FILE EXISTS TO MAKE IMPOSSIBLE. Owner, 2026-08-18, verbatim: *"this is so |
| critical that whenever we do staging, we don't fuck up anyone's data. EVER."* It had already |
| happened once: `fsanyoto/loopable` became STAGING on 2026-08-14 having never been given a store of |
| its own, so two different builds wrote tenant #0's real business data. Compose that with D-305 |
| (the store is last-write-wins at whole-document granularity) and a routine staging deploy does not |
| merely add test rows β it can erase a real user's views, fields and typed cell values. |
| |
| β A DEPLOY FLAG IS NOT THE FIX; THE FLAG IS THE THING THAT ALREADY FAILED. The isolation that |
| existed was bound to a ROLE ("the staging Space"), and a guard bound to a role stops guarding the |
| moment the role moves β which these two Spaces have done twice. So the binding here is on the |
| container's OWN IDENTITY, which no deploy can forget to pass and no role swap can invalidate. |
| |
| ββ THE RULE, AND IT CLASSIFIES THE DEPLOYMENT RATHER THAN THE REPO: |
| |
| 1. the PRODUCTION deployment (identity in `PRODUCTION_SPACES`) -> may write anything |
| 2. any other deployment writing a KNOWN production store -> REFUSED |
| 3. any other deployment writing a repo on its OWN allowlist -> allowed |
| 4. anything else -> REFUSED |
| |
| β WHY NOT CLASSIFY THE REPO, which is the design everybody reaches for first. A DENYLIST of |
| production stores fails OPEN for the next tenant nobody remembered to add. A SUFFIX RULE |
| (`*-staging-data`) pins a SPELLING rather than a claim β see [[gate-pins-a-spelling-not-a-claim]] β |
| and a store named without the suffix is unprotected while reading as protected. Rule 4 is the one |
| that survives a tenant nobody has provisioned yet: an unknown repo is refused, so a store this |
| deployment was never handed cannot be written by accident. |
| |
| ββ AND RULE 4 IS NOT THEORETICAL β IT IS THE HALF OF D-315 THE REGISTER ROW DID NOT KNOW ABOUT. |
| Measured 2026-08-18 by reading both control planes: `royal-imports/cfo-os-staging-data`'s own |
| `tenants.json` is byte-identical to live's and names **`royal-imports/aios-nurilab-data`, |
| `aios-gtmlab-data` and `aios-loopable-data`** β the three other tenants' REAL stores. So |
| `--data-repo=` only ever isolated tenant #0; `harness/runtime.py`'s `store.for_repo(repo)` path |
| resolved three PRODUCTION repos out of the staging store and wrote them, and no flag has ever |
| touched that path. The exposure is FOUR production stores, not one. |
| |
| β READS ARE NOT REFUSED, AND THAT IS A DELIBERATE, STATED SCOPE DECISION. `Store.get` is lenient |
| by contract: a refused read would hand back `{}`, a caller would paint an empty grid, and the whole |
| Space would read as "no data" rather than as "refused" β the exact |
| [[empty-answer-vs-unfinished-answer]] shape this codebase has shipped before. A refused WRITE is |
| loud (503, with the reason). So staging still SEES production data when pointed at it; it can no |
| longer CHANGE it. Narrowing the read is a separate decision and is booked, not smuggled in here. |
| |
| β ABSENT IDENTITY FAILS CLOSED, AND THE FAILURE LOOKS LIKE AN OUTAGE. If a container exposes none |
| of the identity variables, it is treated as "not the production deployment" and every write to a |
| production store refuses. That is the safe direction, but on a live Space it would read as a total |
| product outage β which is why `describe()` reports the RAW observations and not just the verdict: |
| per D-160 the Space environment cannot be read from outside, so the container has to say what it |
| saw. One deploy then answers "does SPACE_ID exist here", instead of three. |
| """ |
| import os |
|
|
| |
| |
| |
| |
| |
| |
| |
| PRODUCTION_SPACES = frozenset({'fsanyoto/runloopable'}) |
|
|
| |
| |
| |
| |
| |
| |
| |
| PRODUCTION_STORES = frozenset({ |
| 'royal-imports/cfo-os-data', |
| 'royal-imports/aios-nurilab-data', |
| 'royal-imports/aios-gtmlab-data', |
| 'royal-imports/aios-loopable-data', |
| }) |
|
|
| |
| |
| PRODUCTION_DEFAULT_STORE = 'royal-imports/cfo-os-data' |
|
|
| |
| |
| |
| _IDENTITY_VARS = ('SPACE_ID', 'SPACE_AUTHOR_NAME', 'SPACE_REPO_NAME', 'SPACE_HOST') |
|
|
| |
| |
| |
| |
| |
| |
| |
| _SANDBOX_STORES_VAR = 'AIOS_SANDBOX_STORES' |
|
|
| |
| |
| |
| |
| |
| _LOCAL_OPT_IN_VAR = 'AIOS_ALLOW_PRODUCTION_DATA' |
|
|
|
|
| class StoreWriteRefused(RuntimeError): |
| """A write this deployment is not allowed to make. |
| |
| β DELIBERATELY NOT A SUBCLASS OF `grid_events.StoreUnavailable`, and the reason is the routes. |
| Several of them carry `except StoreUnavailable:` blocks that DEGRADE to a session-scoped |
| fallback workspace β correct for an outage, catastrophic for a refusal, because the user would |
| be told the change was saved somewhere. A distinct type falls through all of them to the |
| app-level handler, which answers 503 with the reason and never claims a save. |
| """ |
|
|
|
|
| def _env(name): |
| return str(os.environ.get(name) or '').strip() |
|
|
|
|
| def deployment_id(): |
| """This container's own identity, or `''` when it is not a Space (i.e. local dev). |
| |
| β NOT DERIVED FROM ANY DEPLOY ARGUMENT. That is the whole design: `SPACE_ID` is set by the |
| platform inside the container, so it cannot be forgotten, mistyped, or left behind by a Space |
| that changed role without being redeployed. |
| """ |
| sid = _env('SPACE_ID') |
| if sid: |
| return sid |
| author, repo = _env('SPACE_AUTHOR_NAME'), _env('SPACE_REPO_NAME') |
| if author and repo: |
| return f'{author}/{repo}' |
| return '' |
|
|
|
|
| def is_production_deployment(): |
| """True only on the deployment that owns production data. Unknown β False (fail closed).""" |
| return deployment_id() in PRODUCTION_SPACES |
|
|
|
|
| def is_space(): |
| """True when this process is running inside a Space at all. |
| |
| The distinction matters exactly once: a Space that is not production gets NO override, while a |
| laptop does. `deployment_id()` conflates them into `''`, so ask separately. |
| """ |
| return bool(deployment_id()) |
|
|
|
|
| def sandbox_allowlist(): |
| """The repos a non-production deployment may write: `OS_DATA_REPO` + `AIOS_SANDBOX_STORES`.""" |
| allowed = {r.strip() for r in _env(_SANDBOX_STORES_VAR).split(',') if r.strip()} |
| own = _env('OS_DATA_REPO') |
| if own: |
| allowed.add(own) |
| return frozenset(allowed) |
|
|
|
|
| def local_override(): |
| """True when a machine with no Space identity has explicitly opted in to production data.""" |
| return (not is_space()) and _env(_LOCAL_OPT_IN_VAR) == '1' |
|
|
|
|
| def default_store(): |
| """What `OS_DATA_REPO` resolves to when it is unset. |
| |
| ββ FACT (1) OF D-315 DIES HERE: `core/store.py` used to read |
| `os.environ.get('OS_DATA_REPO', 'royal-imports/cfo-os-data')`, so a Space that was never given |
| the key β every NEW Space, by construction β came up bound to tenant #0's real business data. |
| The default now exists ONLY on the deployment that owns it. |
| |
| β IT STILL RETURNS THE PRODUCTION ID ELSEWHERE, RATHER THAN `None` OR `''`, AND THAT IS |
| DELIBERATE. A `None` repo would make `Store.__init__` β which runs at IMPORT time via |
| `_DEFAULT = for_repo(REPO)` β raise or bind something nonsensical, killing the app and every |
| gate on any non-production machine. Returning the real id keeps binding total and lets |
| `write_refusal` refuse the WRITE with a message that names the actual problem. Reads still |
| work, so a developer sees a populated app that will not let them damage it. |
| """ |
| return PRODUCTION_DEFAULT_STORE |
|
|
|
|
| def write_refusal(repo): |
| """`None` if this deployment may write `repo`, else the sentence explaining why not. |
| |
| β RETURNS A REASON RATHER THAN A BOOL, because [[report-the-cause-before-you-fix-it]]: a |
| silent refusal makes every theory about it unfalsifiable, and this one fires on a path where |
| the operator cannot read the container's environment (D-160). |
| """ |
| rid = str(repo or '').strip() |
| if not rid: |
| return ('no store repo is bound. Refusing to guess: an unnamed store is how a deployment ' |
| 'ends up on somebody else\'s data.') |
| if is_production_deployment(): |
| return None |
| if rid in PRODUCTION_STORES: |
| if local_override(): |
| return None |
| who = deployment_id() or 'this machine (no Space identity)' |
| if is_space(): |
| return (f'{who} is not the production deployment, so it may not write {rid}, which ' |
| f'holds real customer data. Point this Space at its own store with ' |
| f'--data-repo=, or add it to {_SANDBOX_STORES_VAR}. There is no override for ' |
| f'a Space: a build that is not live never writes live data.') |
| return (f'{who} may not write {rid}, which holds real customer data. Set OS_DATA_REPO to a ' |
| f'sandbox store, or set {_LOCAL_OPT_IN_VAR}=1 to opt in deliberately (every commit ' |
| f'is then stamped as a local write so it can be told apart afterwards).') |
| allow = sandbox_allowlist() |
| if rid in allow: |
| return None |
| who = deployment_id() or 'this machine (no Space identity)' |
| listed = ', '.join(sorted(allow)) or '(nothing)' |
| return (f'{who} was not given {rid}. A non-production deployment may write only the stores it ' |
| f'was handed: {listed}. Add it to {_SANDBOX_STORES_VAR} if that is intended.') |
|
|
|
|
| def check_write(repo, operation='write'): |
| """Raise `StoreWriteRefused` unless this deployment may write `repo`. The one enforcement door.""" |
| reason = write_refusal(repo) |
| if reason: |
| raise StoreWriteRefused(f'{operation} to {repo!r} refused: {reason}') |
|
|
|
|
| def local_commit_suffix(): |
| """A marker appended to commit messages made under the local override, else `''`. |
| |
| β THIS IS THE SECOND HALF OF D-298's EXIT CONDITION, satisfied rather than argued around: *"a |
| local run either cannot reach the live store without an explicit opt-in, OR stamps its commits |
| distinguishably"*. The measured complaint was that a laptop's commits were titled |
| `update user_tables` β byte-identical to what the live Space writes every few minutes β so a |
| local run and production were indistinguishable in the store's git history, which is the ONLY |
| audit trail this product has. Both clauses now hold: the opt-in is required AND it stamps. |
| """ |
| if not local_override(): |
| return '' |
| import getpass |
| import socket |
| try: |
| who = getpass.getuser() |
| except Exception: |
| who = 'unknown' |
| try: |
| host = socket.gethostname() |
| except Exception: |
| host = 'unknown' |
| return f' [LOCAL DEV {who}@{host}]' |
|
|
|
|
| def describe(repo=None): |
| """What this container sees about itself β the payload behind the status field. |
| |
| β IT REPORTS THE RAW OBSERVATIONS, NOT ONLY THE VERDICT, and that is the point rather than |
| debug noise. D-160 established that a Space's environment cannot be read from outside, so |
| "is staging on the right store?" is a question only the container can answer. A verdict alone |
| ("production: false") cannot distinguish "SPACE_ID says staging" from "SPACE_ID does not exist |
| on this platform at all" β two states with the same verdict and completely different fixes. |
| Reporting the variables makes ONE deploy answer it. |
| |
| β Carries no secret: a Space id and a dataset repo id are public names. The DATA is not, and |
| none of it is here. The field is session-gated anyway (see `routes_admin.settings`). |
| """ |
| rid = str(repo or '').strip() |
| return { |
| 'deployment': deployment_id(), |
| 'production': is_production_deployment(), |
| 'repo': rid, |
| 'writable': write_refusal(rid) is None if rid else False, |
| 'refusal': write_refusal(rid) if rid else None, |
| 'localOverride': local_override(), |
| 'allowlist': sorted(sandbox_allowlist()), |
| |
| |
| 'observed': {name: _env(name) for name in _IDENTITY_VARS}, |
| } |
|
|