fix(build): P0 batch — manifest plugin injection, secret templating, env allowlist, localhost URLs, leftover cleanup#168
Merged
Conversation
…ever silently drop nself build ignored the project manifest entirely: plugins declared under plugins:/bundle:/bundles: in nself.yaml never materialized as containers because the only injection path was DiscoverPluginComposeFiles over ~/.nself/plugins (install-then-discover). Declaring a bundle in config produced a stack with zero of its plugins and no warning. - internal/build/manifest.go: nself.yaml reader (flat + free/pro plugin lists, bundle/bundles expansion via the canonical bundle catalog), ResolveDeclaredPlugins with best-effort auto-install (60s timeout, NSELF_AUTO_INSTALL_PLUGINS=false to disable) and core-service satisfaction (auth/storage) - orchestrator: resolve declared plugins before nginx route injection, np_plugins seed, and compose discovery; report unwired plugins via slog warnings + BuildResult.MissingPlugins - cmd/build: print loud warning with exact fix command when any declared plugin is not wired - DefaultPluginDir: NSELF_PLUGIN_DIR env override (hermetic tests, CI, per-project plugin sets) - tests: N-declared→N-wired repro, missing-plugin report, core-service aliases, placeholder filtering, no-manifest no-op PCI: plugin-injection-dropped (ntask dogfood gap #8)
nself build baked literal secrets (POSTGRES_PASSWORD, Hasura admin
secret, JWT blobs, MinIO root creds, SMTP pass, ...) into the generated
docker-compose.yml. Editing .env was a silent no-op post-build, and any
commit of the generated file leaked credentials (ntask incident
085af2ec; ASI generated-file-secret hard rule).
- internal/build/secrets_template.go: SecretEnvMap + TemplateSecrets
(exact env-key lines -> ${VAR}; alias keys AUTH_JWT_SECRET/
AUTH_DB_PASSWORD value-checked; URL credential positions ':pw@' ->
':${VAR}@' only when no percent-encoding needed) + LiteralSecretLeaks
safety-net warning
- orchestrator Step 8.7 applies templating before write; Step 10.1
writes .nself/compose.env (0600) with all interpolation values
(secrets + console/dev toggles + DATABASE_URL/DOCKER_NETWORK +
plugin env vars)
- internal/docker: Compose.EnvFiles -> --env-file flags
- start/stop/restart/health pass build.ComposeEnvFiles(workdir);
legacy projects without compose.env keep default .env discovery
- tests: real-generator repro (zero literal secrets, refs present),
alias no-clobber, escaped-password guard, 0600 perms, flag order
PCI: compose-secret-templating
nself build warned 'unknown env var' for app-owned vars in real app .env files (NODE_ENV, JWT_SECRET, SSL_AUTO_TRUST, COOKIE_SECRET, ENABLE_DEBUG, LOG_LEVEL, NSELF_PROJECT_NAME — ntask dogfood gap #19). - add the seven app-owned vars to knownEnvVars - add ENV_ALLOWLIST: comma-separated exact names or prefix patterns ending in * (ENV_ALLOWLIST=MY_APP_TOKEN,FEATURE_*) that warnUnknownEnvVars skips — the documented mechanism for project-specific passthrough vars PCI: ntask-dev-env-schema-warnings
nself start printed http://task.local.nself.org-style ready URLs that require undocumented DNS/hosts/mkcert setup and 502 on a fresh machine, while every app doc says http://localhost:<port> (ntask dogfood gap #20). - cmd/commands/start_urls.go: stackURLs(cfg) — default local domains (empty/localhost/local.nself.org) print direct localhost:<port> endpoints (GraphQL, Hasura, Auth, Storage, Mail UI, Admin) plus a 'requires: nself dns-setup' hint for the *.local.nself.org routes; custom domains keep nginx-routed URLs unchanged - tests: local-domain repro, custom-domain regression, port fallbacks PCI: ntask-local-url-mismatch
Interrupted docker compose recreates leave the old container renamed with a hex-id prefix (b6d7b59a1c78_ntask_hasura). The leftover holds ports and shadows the clean <project>_<service> name that app Makefiles and docs rely on (docker exec ntask_hasura — ntask dogfood gap #21). - internal/docker: isRenamedComposeLeftover matcher + cleanupRenamedLeftovers (docker ps -a scan, best-effort rm -f) - RunPreStartCleanup before compose up; also appended to RunPostStartCleanup - tests: matcher table (clean names, other projects, short-hex guards) PCI: ntask-hasura-container-hash-name
acamarata
added a commit
that referenced
this pull request
Jul 3, 2026
- lockstep bump via bump-version.sh (cli 5 files; admin 5 bumped in admin repo) - Changelog: v1.2.2 notes for the P0 build/start fix batch (#168)
This was referenced Jul 3, 2026
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.
Fixes five dogfood-reported build/start bugs that break the simple self-host setup and the Sentry bundle install path.
Fixes
51be7bf9):nself buildignorednself.yamlentirely; declared plugins/bundles never materialized and were silently dropped. Newinternal/build/manifest.goparsesplugins:/bundle:/bundles:, expands bundles via the canonical catalog, best-effort auto-installs missing plugins (disable:NSELF_AUTO_INSTALL_PLUGINS=false), and reports any unwired plugin via loud per-plugin warnings +BuildResult.MissingPlugins+ a printed fix command. Repro test: N declared → N wired.f6fef60a): literal secrets (Postgres password, Hasura admin secret, JWT blobs, MinIO creds) were baked into generated docker-compose.yml. Now emitted as${VAR}refs; interpolation values written to.nself/compose.env(0600) and passed via--env-file. Test asserts zero literal secrets in generated compose.54c469b6): app-owned vars (NODE_ENV, JWT_SECRET, LOG_LEVEL, ...) no longer warn;ENV_ALLOWLIST(exact names +PREFIX_*) for project passthrough.06d93be9):nself startprints reachablelocalhost:<port>endpoints for default local domains instead of unreachable*.local.nself.org; custom domains unchanged.a8210b33): pre/post-start cleanup removes interrupted-recreate rename leftovers (b6d7b59a1c78_<app>_hasura) that shadow clean container names.Verification
go build ./...,go vet ./..., gofmt clean on touched files; 32 new tests green.nself buildin a temp project declaringbundle: nsentry+ 2 free plugins: all 15 declared plugins wired into compose-files.txt; missing-plugin path warns loudly per plugin with exact fix command; generated docker-compose.yml contains zero literal secret values, only${VAR}refs;.nself/compose.envwritten 0600.PCIs: plugin-injection-dropped · compose-secret-templating · ntask-dev-env-schema-warnings · ntask-local-url-mismatch · ntask-hasura-container-hash-name