Commit Graph

21 Commits

Author SHA1 Message Date
cproudlock
316e79db53 Correct the CI claims and the agent tooling's honesty about itself
I asserted that the MySQL migration job "was a comment, not a job" and that
nothing had ever run a fresh install on MySQL. Both wrong. The job existed, hit
this org's ARC runners, and was deliberately moved to internal CI in ffe9fa1cc
because Kubernetes runners without docker-in-docker cannot host service
containers - a fact written at the bottom of the very file I was editing. The
job I added would have failed at container setup on its first push.

Removed it. The leftover was the HEADER, which listed a job that had moved, and
that is now corrected in place with a note not to re-add the entry without
re-adding a job to a runner that can host it. Coverage stays on internal CI.

The api-contract job was green by accident. gen_openapi.py refuses to run while
a bundled plugin is disabled, instance/plugins.json is gitignored, and the step
only worked because the earlier pytest step writes that file at import time and
leaves it. Reordering the steps would have produced a failure about disabled
plugins that had nothing to do with the spec. It now seeds its own registry.
Confirmed against a clean archive of HEAD, where the generator does refuse.

shopdb_whoami claimed to report "what the token is scoped to" and reported the
ACCOUNT's permissions. A read-scoped token on an admin account printed
roles=[admin] and the full permission count, so a model would try a write, take
a 403, and have no tool that explained it. The field is now account_permissions
and carries a note saying a scoped token may allow fewer. Fixing this properly
means /api/auth/me publishing the patscopes claim, which is a separate change.

The MCP client caught only urllib's two error types, so an ordinary mistake
escaped as a raw exception with no cause reaching the caller: a space in a path
raises InvalidURL, a non-ASCII path raises UnicodeEncodeError, a slow read
raises TimeoutError. Paths are now percent-encoded and those escapes are
contained; both cases return the API's own 404 envelope instead.

The operation index collapsed optional authentication. Fourteen routes work
signed out and return more when authenticated, and the index printed them as
requiring a bearer token. They now read bearerAuth,optional.

Also: the generator's own hint told the reader to run "flask plugins enable";
the CLI group is "plugin".

(cherry picked from commit a97346ed81)
2026-09-20 14:50:02 -04:00
cproudlock
1e42356aca Make the API usable by an agent, and stop the contract going stale
Someone writing a script against ShopDB had two options: read a 705 KB spec, or
guess. The spec is the reference, not an index, and handing an agent the whole
thing means either truncating it or spending a context window on 479 operations
nobody asked about.

Three additions, each feeding the next.

/api/docs/operations.txt is the index: every operation on one line with its
method, path, tag, auth and summary, at around 70 KB for all 486. A caller can
hold the entire API at once, find the four operations it needs, and only then
fetch their schemas.

/api/docs/openapi.json?tag=... narrows the spec to one of the 41 tag groups.
Components are kept intact deliberately: pruning the schema graph to match would
leave references resolving to nothing, and a generator that fails confusingly is
worse than a file that is larger than strictly necessary.

tools/mcp/ is an MCP server built on both. Five tools rather than 483, because a
tool per operation is unusable - clients degrade past a few dozen and models
start picking the wrong one. It reads everything from the live instance at call
time, so enabling a plugin adds operations it can already reach with no change
here. The token is the security boundary and the README says so plainly: every
operation the credential permits is reachable, so exploratory work wants a
read-scoped token.

The rest of this is about the contract not drifting, which is what makes any of
the above trustworthy.

Two CI jobs:

- api-contract runs the parity gates and then regenerates the spec and fails if
  anything changed. Those gates already existed and already worked - they caught
  both routes added here, unprompted - but nothing ran them except by hand, and
  the committed spec had silently drifted by three operations, including two
  setup endpoints added the day before.
- migrations-mysql is the job the header comment has been claiming for some
  time while not existing. It described "the REAL multi-site deploy path" and
  "what catches an Alembic regression on MySQL before it ships", and there was
  no such job. That is worse than no comment: it is the false confidence that
  let a migration ship which could not build a schema on a fresh MySQL database.
  The suite runs on SQLite, and SQLite accepts a foreign key onto a table that
  does not exist.

CONTRIBUTING.md now says to run gen_openapi.py --refresh after changing a route,
and that a route the sweep cannot classify belongs in PUBLIC_ENDPOINTS with a
reason rather than hand-edited into the inventory, which the next refresh would
overwrite. The new index route is declared there alongside the spec it indexes.

(cherry picked from commit 762d1b7210)
2026-09-20 14:25:51 -04:00
cproudlock
69a7997dc4 Build the plugin set a real site runs, and write down what shipped
The lean-build job proved the delete-a-plugin guarantee with two plugins and
four hand-picked marker components. It now builds a real twelve-plugin set, and
the assertions follow a rule instead of a hunch: one component from EVERY
omitted plugin must be absent, one from EVERY chosen plugin must be present, and
the backend tree is checked both ways. An omitted set that grows without its
check growing is how a leak ships.

CHANGELOG had not been touched across the whole range, so the largest
security-behaviour change in the product - per-PC endpoint credentials, the
shared-key refusal for enrolled PCs, server pinning, agent 1.20.1 and tray 1.7.1
- had no release record. An [Unreleased] section now carries it, written from
the commits rather than from memory.

CLAUDE.md and the agent quick-reference stated that ADR-016 bans storing
credentials in the registry. It does not, and this fleet depends on HKLM for its
collector key and server pins: the next person following that text removes them
and silently breaks reporting and pinning on every un-enrolled PC. Corrected,
along with two other statements that were false on this branch - the database is
MySQL, not PostgreSQL, and column names are lowercase concatenated, not
snake_case, which is the opposite of what the gate enforces.

The wiki drafts are updated against the code as it stands, each old finding
given a verdict with a file and line rather than left as an assertion from a
week ago, and a new page records the ADR conformance result - including that the
ADR set itself is not on this branch, so nothing here enforces it except the
naming and style script.

They are also scrubbed of the things that must not reach a published wiki: the
site name, the internal git server, developer home paths and the assistant
tooling. They now pass the repository's own publishability patterns, which is
what the scrub is for.
2026-09-18 13:31:25 -04:00
b0bd73f62d Import the wilm agent store, WINC adoption work and batches CLI, with four fixes 2026-09-03 08:16:38 -04:00
bb733f1332 Merge the wilm work, act on the five-agent review, verify the launch-path policy on Windows 2026-09-02 16:15:53 -04:00
2144305433 Add the Darkwing vulnerability scan workflows 2026-09-02 12:17:46 -04:00
2de9c005e8 Merge the smoke-test commits made directly on GitHub
Two commits were made in the GitHub web editor to test whether the self-hosted
runner group was shared with this repository - it is. They branched from
e60945e, while the publication export produced its own two commits from the same
parent, so main here and main on GitHub had diverged and the ff-only push was
correctly refused.

Merging rather than force-pushing: the commits are real history somebody made,
and the wilm branch has already merged them, so discarding them from main would
only delay their return.
2026-08-28 15:33:24 -04:00
a775b87db7 gate guard, runtime spec, Node 24 actions 2026-08-28 15:28:07 -04:00
Proudlock, Cameron1 (GE Aerospace, US)
fa8beca1e2 Fix formatting in smoke.yml workflow file 2026-08-28 15:16:49 -04:00
Proudlock, Cameron1 (GE Aerospace, US)
c0435e7ed1 Add smoke test workflow for runner validation 2026-08-28 15:14:56 -04:00
98badcbc26 publish the runtime spec; gate guard 2026-08-28 14:04:10 -04:00
3d43cb3d86 Windows installer: payload hash-locking, SBOM, client-IP handling, operator docs 2026-08-03 15:08:20 -04:00
ffe9fa1cce CI: drop rsync dep in build-site.sh; move MySQL migration job to internal CI (ARC has no service containers) 2026-07-20 09:01:59 -04:00
5e33189cd9 CI: run on self-hosted arc-runner-set (org IP allow list blocks GitHub-hosted runners) 2026-07-20 08:45:13 -04:00
da28ee9f33 Lean build: always ship core (manifest-less) frontends 2026-07-19 12:10:45 -04:00
99025d10f0 ADR-013 Phase 5: lean per-site builds (build-site.sh + guards + CI) 2026-07-19 00:11:41 -04:00
199438cec9 Add flask seed demo sample data; widen settings.description to TEXT 2026-07-17 20:32:38 -04:00
f255de4097 Add cryptography dependency for MySQL 8 auth 2026-07-17 19:41:43 -04:00
cfa3d1da36 Standardize on Python 3.13 (matches prod 3.13.7) 2026-07-17 19:30:20 -04:00
2afb3027dd Docs audit fixes: kiosk code drift, PowerShell chains, links, leaks, CI auth 2026-07-17 18:06:02 -04:00
9757de50b1 Add GitHub Actions CI + Windows notes on developer docs; neutralize internal-host references 2026-07-17 15:13:35 -04:00