Skip to content

feat(secrets): seal-secret.sh (credential-free) + fuzefront-secrets scaffold - #92

Merged
izzywdev merged 6 commits into
masterfrom
feat/billing-secret-tooling
Jun 23, 2026
Merged

feat(secrets): seal-secret.sh (credential-free) + fuzefront-secrets scaffold#92
izzywdev merged 6 commits into
masterfrom
feat/billing-secret-tooling

Conversation

@izzywdev

Copy link
Copy Markdown
Owner

Adds deploy/scripts/seal-secret.sh <KEY> — hidden prompt → fetch current sealed-secrets public cert from FuzeInfra (stable URL, rotation-safe) → kubeseal --cert --merge-into the manifest in place (preserves other keys). No kubeconfig/cluster access needed (only the public cert seals; FuzeInfra holds the decrypt key). Per-repo scope hard-coded (fuzefront/fuzefront-secrets), --scope/--cert/--in/--manifest overrides.

Also scaffolds deploy/contabo/sealed/fuzefront-secrets.yaml — the SHARED app secret (Authentik/Permit/DB/OAuth/messaging/LLM + billing) with the full key inventory documented and a loud warning never to sync it empty/partial (would clobber the live secret).

Depends on: FuzeInfra exposing the sealed-secrets public cert at a stable URL (separate @claude delegation). Until then, use --cert <local pub.pem>.

🤖 Generated with Claude Code

AppHub Developer and others added 2 commits June 22, 2026 21:55
…ledSecret scaffold

seal-secret.sh <KEY>: hidden-prompt → fetch current public cert from FuzeInfra
(stable URL; handles key rotation) → kubeseal --cert --merge-into the manifest
IN PLACE (preserves other keys). Per-repo scope hard-coded (fuzefront/
fuzefront-secrets), --scope/--cert/--in/--manifest overrides. No kubeconfig: only
the public cert is needed to seal; FuzeInfra holds the decrypt key.

Manifest is the SHARED app secret (Authentik/Permit/DB/OAuth/messaging/LLM +
billing) — documented full key inventory + loud warning never to sync it empty
(would clobber live keys). Populate every key via the script before Argo-wiring.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

CI Fix — shared/dist/kafka recompiled as CommonJS

Root cause: The billing feature commit (#88) accidentally committed shared/dist/kafka/ files compiled with the default tsconfig.json (module: esnext) instead of tsconfig.kafka.json (module: commonjs). This left ESM export * syntax in the committed .js files.

On GitHub Actions, Node.js 22 is now forced on runners. When the backend (a CommonJS process) require()s @fuzefront/shared/kafka, Node.js 22's loadESMFromCJS mechanism detects export * syntax and routes through the ESM loader — which requires explicit .js extensions. Result:

Error [ERR_MODULE_NOT_FOUND]: Cannot find module '.../shared/dist/kafka/types'
    at loadESMFromCJS (node:internal/modules/cjs/loader:1363:24)

The backend never started → Playwright sign-in flow timed out and failed.

Fix: Rebuilt shared/dist/kafka/ with npm run build:kafka (tsc -p tsconfig.kafka.json) to produce proper CommonJS __exportStar(require(...)) output. 13 files changed.

Branch: claude-auto-fix-ci-feat/billing-secret-tooling-27976754207

Note: GitHub Actions token doesn't have PR-create permissions, so this fix is on the branch above and can be merged manually into feat/billing-secret-tooling.

…ead of shared blob

Billing's 3 sensitive keys (STRIPE_SECRET_KEY/STRIPE_WEBHOOK_SECRET/
BILLING_INTERNAL_TOKEN) now live in their OWN SealedSecret 'billing-secrets';
billing-service Deployment references it (DB_PASSWORD/PERMIT_API_KEY stay shared in
fuzefront-secrets). A compromised billing pod can't read Authentik/SMTP/OAuth/LLM
secrets, and sealing/rotating billing keys can't clobber other services. Dropped
the shared-secret scaffold (operator-owned). seal-secret.sh defaults to scope
fuzefront/billing-secrets and is marked an interim copy (canonical tool + cert URL +
methodology owned by FuzeInfra, delegated separately).
@github-actions

Copy link
Copy Markdown
Contributor

CI Autofix — branch pushed for review

I diagnosed the root cause and pushed a fix on branch claude-auto-fix-ci-feat/billing-secret-tooling-27976809122.

Root cause

GitHub Actions is now forcing Node.js 24 on runners that request Node 20 (Node 20 is deprecated). Node 24 supports synchronous require(ESM) — when it encounters a .js file with export statements it tries to load it as ESM, which requires explicit .js extensions on all relative imports.

shared/dist/kafka/index.js (and every file under shared/dist/kafka/) was committed with ESM syntax (export * from './types', import { Kafka } from 'kafkajs', etc.) even though shared/tsconfig.kafka.json specifies "module": "commonjs". The backend's require('@fuzefront/shared/kafka') triggered Node 24's loadESMFromCJS path, which then failed resolving ./types without a .js extension:

Error [ERR_MODULE_NOT_FOUND]: Cannot find module
  '.../shared/dist/kafka/types'
imported from shared/dist/kafka/index.js

Fix

Rebuilt all 12 shared/dist/kafka/**/*.js files as proper CommonJS using TypeScript's __exportStar/__createBinding helpers and require() calls. Also:

  • Added the missing BILLING_LLM_USAGE key to dist/kafka/types.js (stale vs source)
  • Added billing.subscription.changed and billing.usage.recorded to shared/src/kafka/schemas/index.ts (source files existed but were missing from the barrel export)
  • Updated dist/kafka/schemas/index.js to export all 6 schemas consistently

No application logic was changed — only the module format of the pre-committed dist files.

To merge: open a PR from claude-auto-fix-ci-feat/billing-secret-tooling-27976809122feat/billing-secret-tooling.

@github-actions

Copy link
Copy Markdown
Contributor

CI Fix Investigation

Root cause: The shared/dist/kafka/*.js files committed to the repo were compiled with "module": "esnext" (the main tsconfig), producing ESM output with bare re-export specifiers:

```js
// shared/dist/kafka/index.js (broken)
export * from './types';
export * from './schemas';
```

When the backend (CJS) loads @fuzefront/shared/kafka, Node.js 20 detects the ESM export syntax and activates the loadESMFromCJS path. In ESM resolution mode, bare specifiers (no .js extension) aren't resolved automatically → fatal ERR_MODULE_NOT_FOUND for kafka/types, crashing the backend before it could start → Playwright job fails.

Fix: Rebuilt shared/dist/kafka/ with the existing tsconfig.kafka.json ("module": "commonjs") so all dist files use require() — CJS-compatible, no bare-specifier issue.

The fix is on branch claude-auto-fix-ci-feat/billing-secret-tooling-27977466252. A PR couldn't be created automatically (Actions lacks the pull-requests: write permission on this repo), but the branch is pushed and ready. Please open the PR manually or merge it into feat/billing-secret-tooling.

…illing_svc role, DB, secrets)

- values: complete billingService (dbUser=billing_svc, secretName=billing-secrets,
  meterFlushIntervalSec, permitPdpUrl, dbBootstrap) — template referenced these but
  they were undefined (billing never actually deployed).
- billing-db-bootstrap Job (pre-install, idempotent): creates least-privilege
  billing_svc role + 'billing' schema + grants via psql as the superuser. billing-
  service self-migrates its schema on boot as billing_svc.
- ingress carve-out: ONLY /api/v1/billing/webhooks/stripe is public (Exact match,
  Stripe-signature verified); rest of /api/v1/billing stays internal.
- billing-secrets gains BILLING_DB_PASSWORD (billing_svc's password); STRIPE/BILLING
  env always render (dropped the Helm-values guards — SealedSecret provides them).
- values-prod: billingService.enabled=true (fixed a duplicate-key bug that clobbered
  it — billingService was declared twice; merged node-2 affinity into one block).
- Verified: helm lint clean + helm template renders all billing artifacts.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

CI Fix — fix/shared-kafka-cjs-node24

Branch: claude-auto-fix-ci-feat/billing-secret-tooling-27979418842

Root cause

GitHub Actions has deprecated Node.js 20 and is now forcing Node.js 24 on all runners. Node.js 24 detects export * (ESM syntax) in .js files and routes them through the ESM module resolver, which then fails with ERR_MODULE_NOT_FOUND for any extension-less relative import:

node:internal/modules/esm/resolve:1204  throw error;
Error [ERR_MODULE_NOT_FOUND]: Cannot find module
  '.../shared/dist/kafka/types'
  imported from .../shared/dist/kafka/index.js

The shared/dist/kafka/*.js files were compiled using the main tsconfig.json ("module": "esnext") rather than tsconfig.kafka.json ("module": "commonjs"). Every compiled file contained ESM export * from './types' syntax — which Node.js 24 detects and loads as ESM — instead of the CJS require('./types') that the backend expects. This crashed the backend on startup and failed the "Build & start backend" step.

Changes in the fix branch

  1. Rebuilt shared/dist/kafka/ with tsc -p tsconfig.kafka.json → all files now emit proper CJS ("use strict", require(), exports.*).
  2. Excluded src/kafka from shared/tsconfig.json so npm run build can no longer accidentally overwrite the CJS kafka dist with ESM output.
  3. Fixed shared/tsconfig.kafka.json — added explicit "moduleResolution": "node" and "ignoreDeprecations": "6.0" so npm run build:kafka runs cleanly without TypeScript deprecation errors.

To merge this fix, create a PR from claude-auto-fix-ci-feat/billing-secret-tooling-27979418842 targeting feat/billing-secret-tooling.

AppHub Developer and others added 2 commits June 22, 2026 23:10
…rt resolution

Mirror the proven @fuzefront/chat-client fix (#90): billing-ui keeps
@fuzefront/billing-client external, so the host vite/rollup bundle must
statically resolve its named exports. Plain tsc emitted CJS __exportStar(require())
-> 'X is not exported' at host build. tsup emits static ESM re-exports + .d.ts +
.cjs. Adds module/exports map + tsup devDep; tsconfig ignoreDeprecations '6.0'
(TS 6.0.3 baseUrl escalation).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…internal-by-default)

Decision: path-based routing under the single app host, not per-service
subdomains (one cert, no DNS churn, same-origin/no-CORS, shared cookies).
Services internal-only by default; ingress carves out only public paths
(billing's Stripe webhook); browser-facing APIs go through host-backend proxy
with the service's internal token.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

CI Fix: Playwright sign-in flow — postgres health check never passes

Root cause: The pg_isready health check in .github/workflows/e2e.yml has no -d flag:

--health-cmd "pg_isready -U fuzeinfra"

When no database is specified, pg_isready defaults to connecting to a database named after the user (fuzeinfra). That database doesn't exist — only fuzefront_platform is created (via POSTGRES_DB: fuzefront_platform). PostgreSQL logs a FATAL: database "fuzeinfra" does not exist error for every health-check attempt (every 10 s), pg_isready returns a non-zero exit code, and the service is never marked healthy. GitHub Actions times out waiting for the service to become healthy and fails the job before any steps run.

Fix: Add -d fuzefront_platform to the health-check command so it connects to the database that actually exists:

-          --health-cmd "pg_isready -U fuzeinfra"
+          --health-cmd "pg_isready -U fuzeinfra -d fuzefront_platform"

I prepared the one-line fix on branch claude-auto-fix-ci-feat/billing-secret-tooling-27981110757 (commit 9ed8cfd), but the GitHub App token used by the auto-fix bot lacks the workflows scope required to push changes to .github/workflows/ files. The fix can be applied manually or via a token with workflows permission.

@github-actions

Copy link
Copy Markdown
Contributor

CI Fix Investigation

The Playwright sign-in flow job fails because the backend never starts:

Error [ERR_MODULE_NOT_FOUND]: Cannot find module '.../shared/dist/kafka/types'
imported from .../shared/dist/kafka/index.js

Root Cause

The billing feature commit (64034d7) rebuilt shared/dist/kafka/ using the main tsc (configured with "module": "esnext" in tsconfig.json), producing ESM output. When the CJS backend tries to require('@fuzefront/shared/kafka'), Node.js 20 detects the ESM syntax (export * from './types') and falls through to loadESMFromCJS, where ESM resolution requires explicit .js extensions — ./types has none, so it fails.

The fix is to use tsc -p tsconfig.kafka.json ("module": "commonjs") to rebuild shared/dist/kafka/, producing CJS files that require() handles correctly.

Fix

Branch claude-auto-fix-ci-feat/billing-secret-tooling-27981242714 contains the fix: rebuilt shared/dist/kafka/*.js as CJS via tsconfig.kafka.json. Push is live — please open a PR from that branch into feat/billing-secret-tooling (GitHub Actions is not permitted to create PRs in this repo).

@github-actions

Copy link
Copy Markdown
Contributor

CI Fix — branch claude-auto-fix-ci-feat/billing-secret-tooling-27994827297

Root cause

The Email Integration (MailHog) job failed because the CI step runs:

cd services/email-service && npm ci

…but services/email-service/ had no package-lock.json. npm ci requires a lockfile and exited with code 1 (printing its usage/help text). The Notify Team job then failed as a downstream consequence.

Fix (2 files, no CI workflow changes)

  1. services/email-service/package.json — changed @fuzefront/shared from a bare version ref ("1.0.0") to a file: path ("file:../../shared"), matching the pattern already used by services/billing-service.
  2. services/email-service/package-lock.json — generated by running npm install after the above change.

The fix is pushed to branch claude-auto-fix-ci-feat/billing-secret-tooling-27994827297. Please open a pull request from that branch into feat/billing-secret-tooling to apply it.

🤖 Generated with Claude Code

@github-actions

Copy link
Copy Markdown
Contributor

CI fix pushed — branch ready for PR

Failing jobs: Email Integration (MailHog), Notify Team
Fix branch: `claude-auto-fix-ci-feat/billing-secret-tooling-27994777298`

Root cause

`services/email-service` was never added to the root `package.json` workspaces array, even though the service's Dockerfile already used the workspace-root approach (`npm ci --workspace=services/email-service`).

Because it was not registered, the root `package-lock.json` had no entry for it. The CI step:

```yaml

  • name: Install email-service deps
    run: cd services/email-service && npm ci
    ```

failed because `npm ci` requires a lock file and `@fuzefront/shared` is a private monorepo package not published to npm — so there was no way to resolve it in a standalone install.

The Notify Team job cascaded because `email-integration` returned `failure`.

Fix (2 files, no workflow changes)

  • Added `"services/email-service"` to `workspaces` in root `package.json`
  • Regenerated `package-lock.json` so the workspace and its `@fuzefront/shared` link are resolved

npm 7+ automatically detects the workspace root when `npm ci` is run from a workspace-member subdirectory, so the existing CI step works without modification.

Verification

`cd services/email-service && npm ci --dry-run` passes after the workspace registration (confirmed locally on this runner).

Please open a PR from `claude-auto-fix-ci-feat/billing-secret-tooling-27994777298` → `feat/billing-secret-tooling` to merge the fix.

@github-actions

Copy link
Copy Markdown
Contributor

CI fix ready — branch claude-auto-fix-ci-feat/billing-secret-tooling-27995248439

Root cause

The Email Integration (MailHog) job failed because services/email-service had no package-lock.json. npm ci strictly requires a lockfile and errors out when one is absent.

A secondary issue was that @fuzefront/shared was declared as a bare version ("1.0.0") rather than a local file reference. Running npm install standalone would try to fetch the package from the npm registry, which would also fail since it's a local-only package.

Fix

  1. Changed "@fuzefront/shared": "1.0.0""@fuzefront/shared": "file:../../shared" in services/email-service/package.json (matching the pattern already used by billing-service).
  2. Generated services/email-service/package-lock.json by running npm install, which is what npm ci requires.

The Notify Team failure was a cascade — it exits 1 whenever any upstream job fails; it will pass once the email-integration job is fixed.

Branch

Changes are pushed to claude-auto-fix-ci-feat/billing-secret-tooling-27995248439. Please create a PR from that branch into feat/billing-secret-tooling (GitHub Actions is not permitted to create PRs in this repo).

🤖 Generated with Claude Code

@github-actions

Copy link
Copy Markdown
Contributor

CI fix pushed — branch `claude-auto-fix-ci-feat/billing-secret-tooling-27996506999`

Root cause

The Email Integration (MailHog) job calls `npm ci` inside `services/email-service`, but two things were wrong:

  1. Missing `package-lock.json` — `npm ci` unconditionally requires a lockfile; without one it prints the npm help/usage text and exits 1.
  2. Wrong `@fuzefront/shared` version specifier — `package.json` listed `"@fuzefront/shared": "1.0.0"` (a registry version specifier), but the package is only available as a local workspace path. The sibling `billing-service` correctly uses `"file:../../shared"`. Without the right specifier, `npm install` can't resolve the dependency.

The Notify Team failure is purely downstream — it echoes failure and exits 1 whenever any upstream job fails.

Fix (commit `1f15386`)

  • Changed `@fuzefront/shared` to `"file:../../shared"` in `services/email-service/package.json`
  • Generated `services/email-service/package-lock.json` via `npm install --package-lock-only`

Verified with `npm ci --dry-run`: exits 0, resolves 427 packages.

Please merge `claude-auto-fix-ci-feat/billing-secret-tooling-27996506999` → `feat/billing-secret-tooling` to unblock this PR's CI.

@github-actions

Copy link
Copy Markdown
Contributor

CI Fix Analysis — branch claude-auto-fix-ci-feat/billing-secret-tooling-27997600561

Root Cause

The Email Integration (MailHog) job failed at:

cd services/email-service && npm ci

npm ci requires a package-lock.json in the target directory (or a parent workspace). services/email-service/ had neither — the service was missing from the root workspaces array in package.json, and had no local lockfile. npm responded by printing its usage help and exiting 1.

The Notify Team failure is a downstream consequence.

Note: the service's own Dockerfile already uses npm ci --workspace=services/email-service (expecting workspace membership from the root) — so it was always intended to be a workspace, just never declared as one.

Fix (committed to claude-auto-fix-ci-feat/billing-secret-tooling-27997600561)

  1. Added "services/email-service" to the workspaces array in package.json.
  2. Regenerated package-lock.json (npm install --package-lock-only --ignore-scripts) so the root lockfile covers the service's dependency tree.

With this, cd services/email-service && npm ci finds the root workspace lockfile, resolves @fuzefront/shared as a local workspace symlink, and succeeds.

Note: GitHub Actions bot cannot create PRs in this repo — pushing the fix branch and leaving this comment instead. The fix is ready to merge into feat/billing-secret-tooling.

@github-actions

Copy link
Copy Markdown
Contributor

CI fix — branch ready for review

The Email Integration (MailHog) job was failing because services/email-service was not listed in the root package.json workspaces array. Without a workspace entry, no root package-lock.json entry is generated for it, and npm ci inside the directory exits with code 1 (no lockfile found). The Notify Team job then fails as a downstream consequence.

The Dockerfile for the service already used --workspace=services/email-service with the comment "needed so npm ci can resolve workspace links" — confirming workspace membership was always the intended design.

Fix applied on branch claude-auto-fix-ci-feat/billing-secret-tooling-27997598131

  • package.json — added "services/email-service" to the workspaces array
  • package-lock.json — regenerated via npm install --package-lock-only; @fuzefront/shared resolves locally through the existing shared workspace

With the root lockfile updated, npm ci inside services/email-service/ traverses up to the root lockfile (standard npm 10 workspace behaviour on Node 20), unblocking the failing job.

Please merge claude-auto-fix-ci-feat/billing-secret-tooling-27997598131feat/billing-secret-tooling to fix the CI.

@izzywdev
izzywdev merged commit 90e8406 into master Jun 23, 2026
15 of 20 checks passed
@izzywdev
izzywdev deleted the feat/billing-secret-tooling branch July 27, 2026 18:27
@izzywdev
izzywdev restored the feat/billing-secret-tooling branch July 29, 2026 05:10
izzywdev added a commit that referenced this pull request Aug 16, 2026
#669)

The postprod-smoke@fuzefront.com account was provisioned on an earlier CI
run. Since then POST_PROD_PASSWORD and the Authentik-stored password have
drifted, causing every run of test 7 to hit a 401 on
POST /api/v1/security/session and hard-fail (runs #76#92).

Root cause: the email-available check returns `available: false` (account
exists), so the spec falls into the sign-in branch and fails with 401 instead
of self-provisioning.

Fix: when sign-in returns 401 and AUTHENTIK_ADMIN_TOKEN is available, the
spec now:
  1. Calls GET https://auth.fuzefront.com/api/v3/core/users/?email=<EMAIL>
     to find the Authentik user's numeric pk (mirrors accountApi.ts findUserPk).
  2. Calls POST .../set_password/ to reset the password to POST_PROD_PASSWORD
     (mirrors accountApi.ts setUserPassword).
  3. Retries POST /api/v1/security/session — now passes.
  4. Annotates the test result so the self-heal is visible in the report.
Without AUTHENTIK_ADMIN_TOKEN the spec fails with a clear diagnostic rather
than looping silently on 401.

Workflow changes: thread AUTHENTIK_ADMIN_TOKEN through
prod-post-deploy.yml → post-prod-e2e.yml → the "Run post-prod smoke" step env.


Claude-Session: https://claude.ai/code/session_01VDvprmS9SwG7vcVZum7RDM

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant