feat(compose): extend CS_N custom services with image, env-file, and volume mounts - #408
Merged
Merged
Conversation
…ownloaded A plugin with a binaryName has downloadPluginPackageForTier try its per-platform release asset first, falling back to the source tarball only when that download fails. But the registry carried exactly one checksum per plugin (the source tarball's), and installLocked always verified against it regardless of which artifact was actually on disk — so any binaryName plugin whose per-platform asset downloaded successfully had its platform tarball's bytes hashed and compared against the source tarball's checksum, which can never match. downloadPluginPackageForTier now reports which artifact it fetched (ArtifactKindSource, or a platform string from PlatformArch()) alongside the path. installLocked resolves the checksum that matches via the new resolveArtifactChecksum: the source artifact uses manifest.Checksum exactly as before (including its existing FIX-CLI-6 warn-and-proceed leniency when empty); a platform artifact uses the matching entry in the new PluginManifest.PlatformChecksums map, parsed from the registry's checksums.platforms object. A platform artifact with no matching registry checksum is refused unconditionally — it never falls through to the source-checksum leniency, and no env var (NSELF_PLUGIN_REQUIRE_CHECKSUM included) changes that. That leniency exists for the documented, tracked source-checksum coverage gap; it was never a license to install a downloaded executable with zero verification. A release that predates PlatformChecksums, or one platform whose checksum was never backfilled, is a registry data gap to fix upstream, not a flag to bypass here. PlatformChecksums round-trips through the registry cache (Registry.MarshalJSON) the same way every other field in this package must, per TestRegistryRoundTripLosesNoField.
… policy resolveArtifactChecksum: the source artifact always uses manifest.Checksum (including the empty-string case, left for verifyChecksum's own leniency to handle); a platform artifact resolves to its matching PlatformChecksums entry, never the source checksum or a different platform's; a platform artifact with no matching entry is refused regardless of NSELF_PLUGIN_REQUIRE_CHECKSUM, a present source checksum, or whether the map is nil versus just missing that one key. Three end-to-end tests exercise the same policy through verifyChecksum: a correct platform checksum passes, a mismatched one is rejected (mirroring the existing source-checksum mismatch test), and a missing one never reaches verifyChecksum's lenient empty-string branch at all.
…ile cap The per-artifact checksum change pushed this file to 309 lines, past the engineering-standard cap enforced by internal/repoqa's TestFileSizeBudgetNotExceeded (budget: 0 files allowed over). Tightened the new Step 5 comments and removed a pre-existing duplicated sentence in the Step 4 comment — no behavior change, same logic, back to 300 lines exactly.
…volume mounts nself build could not express a pinned image digest, injected SMTP env vars, or an extra volume mount for a custom service, so any stack needing them had to be hand-authored into a docker-compose.override.yml that nself build would silently drop on a rebuild (G-013). Adds three env vars to the CS_N model, all declarable in .env: - CS_N_IMAGE: run a pre-built image (optionally digest-pinned via @sha256:...) instead of building from a Dockerfile. Mutually exclusive with CS_N_PATH. - CS_N_ENV_FILE: inject KEY=VALUE pairs from a dotenv-format file, applied after CS_N_ENV_PASSTHROUGH and before CS_N_ENV. Handles values CS_N_ENV's comma-joined format cannot represent safely (e.g. a password containing a comma), and many-var cases like SMTP config. - CS_N_VOLUMES: comma-separated host:container[:mode] bind mounts, appended to the generated service. Generator gains WithWorkDir to anchor CS_N_ENV_FILE reads to the project root; the build orchestrator now threads st.workdir through so CS_N_ENV_FILE resolves correctly regardless of invocation directory. buildCustomService and Generate() now return an error on a missing/ unreadable CS_N_ENV_FILE rather than silently omitting the vars.
Merged
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.
Summary
Closes CLI gap G-013:
nself buildcould not express a pinned imagedigest, injected SMTP env vars, or an extra volume mount for a custom
service. The ntask production stack needed all three, so it was
hand-authored into
docker-compose.override.yml— invisible tonself buildand silently lost on any CLI-only rebuild.Extends the existing CS_N custom-service model (no new mechanism) with
three new env vars, all declarable in
.env:CS_N_IMAGE— run a pre-built image (optionally digest-pinned via@sha256:...) instead of building from a Dockerfile. Mutuallyexclusive with
CS_N_PATH.CS_N_ENV_FILE— injectKEY=VALUEpairs from a dotenv-format file,applied after
CS_N_ENV_PASSTHROUGHand beforeCS_N_ENV. Handlesvalues
CS_N_ENV's comma-joined format can't represent safely (e.g.a password containing a comma) and many-var cases like SMTP config.
CS_N_VOLUMES— comma-separatedhost:container[:mode]bind mounts,appended to the generated service.
Example expressing the three ntask requirements:
GeneratorgainsWithWorkDirto anchorCS_N_ENV_FILEreads to theproject root; the build orchestrator now threads
st.workdirthroughso it resolves correctly regardless of invocation directory.
buildCustomService/Generate()now return an error on a missing orunreadable
CS_N_ENV_FILErather than silently starting the servicewithout the vars it needs.
coreEnvVarswas refactored into smaller named steps(
fixedCoreEnvVars/addOptionalStoreEnvVars/applyEnvPassthrough/applyExtraEnv) while adding this — it was already over the repo's50-line function cap before this change.
Docs:
.github/wiki/Config-Custom-Services.mdreference table + notesupdated (this also fixes a pre-existing doc/code drift: the page
already forward-referenced
CS_N_IMAGEas "advanced usage" before itexisted in code).
Test plan
go build ./...cleangofmt -l .clean,make vetclean,golangci-lint runcleango test ./...— 5139 tests pass across 98 packages (no regressions)mutual exclusion, path traversal, volume entry shape) and
compose-time behavior (image skips build, volumes appended,
env-file precedence order, missing env-file fails loudly)
internal/composecoverage 90.1%,internal/configcoverage 80.5%(both above the 70% gate)
make cmd-inventoryre-run: no diff (no new commands added, asexpected for an env-var-only extension)