Module Publishing Prerequisites¶
This is the authoritative prerequisite ladder for publishing an HLA-Compass module with SDK 5.9.2 and its matching platform release. Scientific modules require their own tests after rebuilding; installing the SDK does not establish that a scientific workflow has completed successfully.
Start with Tier 1. Use Tier 2 only when the module cannot use the platform-managed runtime image.
Baseline for Both Tiers¶
- Python 3.11 through 3.14.
- An invited HLA-Compass account with membership in the target organization.
- The current SDK release installed in an isolated environment.
- A module that passes
hla-compass validateand its domain tests.
Docker is required to generate the Linux dependency lock with hla-compass lock
and for containerized local testing/development. A fresh scaffold needs that
lock before publishing. Once a matching lock has been generated and committed
by an author or CI, Docker is not required merely to submit its source archive.
Install the authoring extra when running scaffold tests locally.
Tier 1: Source Upload (Default)¶
Use this tier unless the module needs a custom system runtime or a prebuilt image. The platform generates the canonical build recipe, pushes the final image to managed ECR, waits for the blocking Inspector scan, records platform-owned source-build evidence, and registers the digest. Source upload does not accept a caller-supplied Dockerfile.
Managed source publication requires a complete artifact-hashed
backend/requirements.lock.txt that is current with
backend/requirements.txt; missing, unhashed, stale, or incomplete locks are
rejected before Docker starts. Generate it with hla-compass lock from the
module directory; the scaffold's INTEGRATIONS.md explains the target runtime.
Only non-managed local authoring may warn and synthesize an unlocked install for immediate development.
Modules that declare manifest.mcp.tools must also follow the
native-MCP finite handler source contract.
For an existing module, hla-compass skill update refreshes guidance but does
not perform the required executable-source and manifest migration.
Managed source intake performs two distinct checks. The security-relevant
check is platform-owned, constrained static AST and manifest-schema analysis
of the bounded source archive. It does not import or execute publisher Python.
A successful check records structured mcpEntrypointValidation evidence bound
to the canonical manifest, source archive, and digest-pinned image. The managed
source callback accepts that evidence only from the content-addressed CodeBuild
publication attestation. Publication, run admission, and later lifecycle
transitions continue to require the matching persisted evidence; a source
archive marker alone is not publication authority.
Separately, after installing the declared dependencies and copying the module
source, the canonical image build repeats ModuleValidator entrypoint checks
offline as the final numeric non-root runtime identity, with HOME and
language caches redirected to /tmp. This imports publisher Python and can
therefore execute module-level code even though native MCP callables are never
invoked. It is a cooperative build-quality smoke test—not a hostile-code
sandbox, security boundary, or the fact proved by the attestation. Missing,
non-callable, async, or signature-incompatible declarations still fail the
build before the image can be pushed or registered.
Release availability is intentionally fail-closed. The current release enables
Lambda, Fargate, Batch, and with-ui source builds with reviewed exact-digest
runtime and UI-builder pins. The platform loads a published UI only after its
trust checks and integrity hash are available; see UI modules.
Use Tier 2 only when the workload requires a custom image; do not use it to bypass a failed security gate.
You do not need:
- a container registry or GHCR namespace;
- registry pull credentials;
- Cosign keys or GitHub OIDC signer trust; or
- permission to push container images.
For a manual dev/staging publish, install the exact TestPyPI candidate with dependencies from PyPI, then authenticate interactively:
python -m venv .venv
source .venv/bin/activate
python -m pip download --index-url https://test.pypi.org/simple/ --no-deps --only-binary=:all: --dest sdk-wheel "hla-compass==5.9.2"
python -m pip install "hla-compass[authoring]==5.9.2" --index-url https://pypi.org/simple/ --find-links sdk-wheel
hla-compass auth login --env dev
hla-compass init peptide-summary --template lambda
cd peptide-summary
python -m pip install -r backend/requirements.txt
hla-compass lock
hla-compass validate --strict
python -m pytest
hla-compass test --input examples/sample_input.json
hla-compass publish \
--env dev \
--scope org \
--idempotency-key peptide-summary-1.0.0-release-1 \
--wait
For CI, create a Module publishing API key in the HLA-Compass profile,
store it as the repository secret HLA_COMPASS_API_KEY, and use the
.github/workflows/publish.yml included in every current scaffold. The key is
publish-only and bound to one organization; it must not be reused for data or
MCP access.
Verify the key before relying on it: hla-compass auth status --check performs
a real authenticated call and exits non-zero if the credential cannot be used.
Plain auth status only prints a table and always succeeds, so it is not a
gate. The shipped workflow uses --check.
The publish is successful only when the CLI reports a terminal successful intake status. An upload receipt or local image build is not proof that the version is deployable.
A build can outlast the CLI wait period. --wait gives up after its --timeout
and exits 75, which means the client stopped watching, not that the publish
failed; a genuine failure exits 1. On 75, poll
hla-compass publish-status --env <env> <publishId> rather than republishing.
Tier 2: Custom Image (Advanced)¶
New Fargate and Batch custom images must declare USER 1000:1000, a canonical
absolute non-root WORKDIR, and exactly one writable volume at /tmp. Intake
checks the image filesystem: the working directory and ancestors must be real,
traversable directories; /tmp must be writable and traversable by that user.
The deployed root filesystem is read-only. Use the generated SDK Dockerfile as
the contract and move scratch/cache/output writes to /tmp; adding USER to an
otherwise incompatible image is insufficient. Publication rejects incompatible
images instead of silently rewriting them. This does not retrofit historical
definitions or change the existing external Nextflow runner.
Use this tier only when Tier 1 cannot supply the runtime required by the module. It adds an external image supply chain and therefore requires all of the following:
- an organization-approved registry namespace such as
ghcr.io/acme-bio/*; - a dedicated machine pull credential configured in HLA-Compass for that namespace;
- an approved
github_actions_oidcsigner policy matching the source repository and workflow identity; - a GitHub Actions job with
contents: read,packages: write, andid-token: write; and - an SDK manifest-signing RSA keypair. The default location is
~/.hla-compass/keys/{private,public}.pem(or$HLA_COMPASS_CONFIG_DIR/keys/). Generate it once, when missing, with the CLI--generate-keysoption. Storeprivate.pemin an approved secret manager or encrypted backup with restricted access, retainpublic.pemwith the release records, and never commit either key; and - the same organization-bound, publish-only HLA-Compass API key used by Tier 1 CI.
For a reviewed manual custom-image release, use an immutable digest and run the platform preflight before publication:
IMAGE_REF="ghcr.io/acme-bio/peptide-summary@sha256:<digest>"
# Creates the SDK manifest-signing keypair only when it is missing.
hla-compass verify-image \
--env dev \
--image-ref "$IMAGE_REF" \
--scope org \
--generate-keys
# Reuses that keypair; the verified digest is the published digest.
hla-compass publish \
--env dev \
--image-ref "$IMAGE_REF" \
--scope org \
--idempotency-key peptide-summary-1.0.0-image-release-1 \
--wait
Tier 2 does not support native MCP capabilities. A custom-image request whose
manifest contains a non-empty mcp.tools array is rejected with
UNSUPPORTED_PUBLICATION_PATH, including dry runs. The canonical request,
legacy container and superuser adapters, asynchronous intake, callback, and
later publication/run-admission checks all fail closed on this boundary. Use
Tier 1 source upload for every module that declares a native MCP tool.
The reason is deliberate: an image-only request does not provide the bounded
managed source input required for platform-owned static AST/schema analysis,
and the platform does not execute arbitrary custom-image code during
privileged intake. It therefore cannot produce the required native-MCP
attestation. Running hla-compass validate --strict against the exact source
remains a useful authoring check, but it does not authorize a Tier 2 native-MCP
publication. Signature, manifest-signature, mirroring, SBOM, and blocking
image-scan gates still apply to eligible Tier 2 images; none substitutes for
the managed-source evidence.
If the preflight is intentionally performed elsewhere, the first publish
may use --generate-keys instead. The option creates missing keys; it does not
rotate an existing pair. A CI workflow that generates keys on an ephemeral
runner must persist the private key in an approved secret store when signer
continuity or later reproduction is required.
No custom-image reusable workflow is currently published for external callers.
The platform workflow repository is private and does not currently grant
cross-repository Actions access, so a caller cannot load it; a mutable
@main reference would not be an acceptable release boundary even if access
were enabled. Until a reviewed workflow is released from an accessible
repository and identified by its full-length commit SHA, use Tier 1 or a
separately reviewed caller-owned Tier 2 workflow that installs one exact
released hla-compass version from PyPI. Do not check out or install arbitrary
platform repository source in a job holding registry, OIDC, or publish
credentials.
Do not use a personal registry token or a developer password as a CI credential. Registry access must use a dedicated machine identity, and module publication must use the publish-only platform key.
Choosing a Tier¶
| Requirement | Tier 1 source upload | Tier 2 custom image |
|---|---|---|
| Platform-managed container build and scan | Yes | No |
| GHCR or another approved registry | No | Yes |
| Registry machine pull credential | No | Yes |
| GitHub OIDC signer trust | No | Yes |
| SDK manifest-signing keypair | No | Yes |
| Platform-owned attested static AST/schema validation | Yes | No |
Offline non-root ModuleValidator import smoke |
Cooperative quality check | Not run during image intake |
Native MCP (manifest.mcp.tools) |
Supported with attested validation | Rejected |
| Publish-only HLA-Compass API key for CI | Yes | Yes |
| Interactive HLA-Compass login for manual publish | Yes | Optional |
If there is uncertainty, choose Tier 1. Moving to Tier 2 is an organization and security-policy decision, not a normal scaffold requirement.