Feature: /etc/dashcaddy/operator.env (root-owned KEY=VALUE file) is forwarded into the DashCaddy container as docker -e flags by start.sh. Canonical flag: ALLOW_LIFETIME_LICENSE=true on the CREATOR host only. This is a client-side rail, NOT the security boundary: lifetime codes must HMAC-verify against the creator-only signing secret, which is never shipped to customers (installs carry only .license-secret-hash; the license server never issues lifetime codes). Flipping the flag on a customer host grants nothing. Missing file = normal case (zero flags). Design (per r3 judge blockers): 1. scripts/operator-flags.js — Node, ONE file descriptor: opened with O_RDONLY|O_NOFOLLOW, fstat'ed, and read from that SAME fd. Contract: regular file; no group/other access bits (mode & 077 == 0); no setuid/setgid/sticky; owner uid 0 under root runtime (euid => owner equality otherwise). Symlink refused at open even when the target would pass all checks. No stat-path/reopen-path TOCTOU window. Violation => stderr FATAL + exit 3. Content is pure data: never sourced/evaled/executed; `$(...)` values stay inert text. 2. start.sh: rc 3 => warn + forward NOTHING (fail closed); ANY other non-zero rc => ABORT startup (fail loud, tested policy); missing file => silent zero overrides. Single helper invocation; keys-only audit line at boot (never values). 3. Artifact hygiene: verifier asserts zero full-format license codes in any submission file. (An earlier round leaked one; that code is dead — signing secret rotated, keygen verify reports INVALID.) Root-cause hardening (2026-10-08 incident: deploy checkouts overwriting git-TRACKED runtime state revoked the owner's premium and hid service cards): - untrack dashcaddy-api/data/services.json (stale committed copy had clobbered the live 16-service state incl SamiMail/SamiPanel/Revenue) - untrack dashcaddy-api/.license-secret + .license-counter, extend .gitignore. The secret value in prior git history is already rotated, hence cryptographically dead. Tests: 16 executed operator-flags tests (O_NOFOLLOW symlink-to-valid- target, 0644/0755/setuid/directory/foreign-owner rejections, missing-file-silent, usage error, injection-inert, translation suite); license-manager 76 + tier-enforcement 21 untouched => 113 targeted green.
35 lines
1.0 KiB
Plaintext
35 lines
1.0 KiB
Plaintext
# Dependencies
|
|
node_modules/
|
|
|
|
# Runtime state/config files (generated, not source)
|
|
# Note: data/ subdir contains runtime state (credentials, secrets, history) — never commit
|
|
dashcaddy-api/data/
|
|
dashcaddy-api/credentials.json
|
|
dashcaddy-api/.env
|
|
.env
|
|
dashcaddy-api/alert-config.json
|
|
|
|
# Build artifacts
|
|
*.log
|
|
*.tar.gz
|
|
|
|
# Local artifacts
|
|
CLAUDE.md
|
|
|
|
# Runtime state directories
|
|
backups/
|
|
updates/
|
|
|
|
# Generated post-deploy patch artifacts — flat copies of src/ files placed
|
|
# in dashcaddy-api/ root by scripts/dashcaddy-post-deploy-patches.sh to work
|
|
# around broken upstream tarballs. Real source lives in dashcaddy-api/src/.
|
|
# Once v1.15.0 ships src/ properly, these become obsolete.
|
|
dashcaddy-api/*.js
|
|
!dashcaddy-api/license-keygen.js
|
|
!dashcaddy-api/platform-paths.js
|
|
# DC-164: runtime license material must NEVER be repo-tracked — a deploy
|
|
# checkout overwriting the live signing secret revokes activations (incident 2026-10-08).
|
|
dashcaddy-api/.license-secret
|
|
dashcaddy-api/.license-counter
|
|
dashcaddy-api/data/services.json
|