Repository navigation
feat: registry manifest, and refuse unregistered process addresses at submission - #184
Merged
Merged
Conversation
… submission Strategy decision 5, phase A. compose_api/registry/manifest.yaml is the registry of record: pinned entries with module roots, a curation level and the evidence for it. /simulation/run now reads every composite document in the upload, nested bundle archives included, and refuses any address that is not local:<module>.<Class> under an entry at level tested or higher in the registry_env bundle, with a 400 naming each one. Until now nothing was checked: the upload went to the cluster byte for byte, the allow-list was built and ignored, and the container honours local:!module (arbitrary import) and the rest/parallel protocols. Those unsafe forms are refused even under address_policy=warn. Also: an unsupported file suffix is a 400, not a 500; the unused PBAllowList and hardcoded allow_list are removed. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A prebuilt simulator's image brings its own processes, which the registry manifest does not describe, so /simulation/run checks a `simulator=<name>` submission's name against settings.prebuilt_simulators and skips the address check (the deployment vouches for the image by listing it). Unlisted names are refused before the registry is consulted. The #190 test drops the pip allow list this branch removes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
jcschaff
added a commit
that referenced
this pull request
Oct 6, 2026
…log ingest Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
jcschaff
added a commit
that referenced
this pull request
Oct 6, 2026
….6.0 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Strategy decision 5, phase A (manifest and enforcement). This closes goal G6's done-test: the service rejects a composite naming an unregistered process address, or a component below tested*, with a clear message.* Catalog ingest, the rest of phase A, follows in a separate PR.
What was true before this
Nothing was checked:
/simulation/runwrote the upload to a temp file and handed it to the cluster byte for byte.PBAllowListwas built from a hardcoded package list and ignored byrun_simulation.determine_dependencieswas never called, and it lets everylocal:address through in any case.allocate_core()registers every installed process under its full and short name. It honourslocal:!module.Class, which imports any module, and therest:andparallel:protocols.What this adds
compose_api/registry/manifest.yamlis the registry of record. Each entry is pinned (byversionorcommit) and carriesmodule_roots, a curationlevelon the five-rung ladder,bundles, and theevidencefor its level. The pydantic schema inmanifest.pyrequires a pin and unique ids, and matches modules by longest root.It is seeded with the two packages behind today's
registry_env:pbsim-commonpb-multiscale-actinBoth are grandfathered at tested. The evidence text says plainly that the gate is our cluster tests, not the packages' own suites, until phase B computes levels.
compose_api/registry/validation.pyopens every composite document in the upload, including archives nested in a batch bundle. It checks all of them, because the container runs whichever one it finds first, and collects everyaddressin string or{protocol, data}form. It refuses:warnlocal(rest:,parallel:)local:!…local:CopasiUTCStep)registry_envA quoted type default under an
addresskey, as in the SED-ML template, is a type declaration rather than an address, and is not collected.Router.
detailis{message, violations: [{document, address, reason, always_rejected}]}. It is declared in the OpenAPI spec (+4 lines), and the rejected upload's temp file is deleted.Setting
address_policy: enforce | warn, defaultenforce.warnis an escape hatch if enforcement blocks a real user.Removed:
PBAllowList, the hardcodedallow_list, thepb_allow_listparameter, and the commented-out allow-list test.Compatibility
Every address today's clients send passes:
phase_cycle.omex,readdy.omex, and the rendered COPASI and Tellurium curated templates are all tested. pbest submits fully qualifiedlocal:names, so it is unaffected. The one known short-name use is in pbest's own tests, which call the engine locally rather than this service.Tests
tests/registry/test_validation.py(22) andtests/registry/test_manifest.py(6) need no services. They cover every refusal row above, nested bundles, a bad document hiding behind a good one, unreadable archives, both policies, and SBML.tests/api/test_submission_rejection.py(4) checks the 400 end to end through the app.make checkclean.Docs
CLAUDE.mddescribes the check and notes that a new simulator needs both a manifest entry and a library insimulator_registry.json.🤖 Generated with Claude Code