Skip to content

fix(security): remove internal infra hostnames from published package#18

Open
andrei-hasna wants to merge 1 commit into
mainfrom
fix/security-remove-internal-infra-hostnames
Open

fix(security): remove internal infra hostnames from published package#18
andrei-hasna wants to merge 1 commit into
mainfrom
fix/security-remove-internal-infra-hostnames

Conversation

@andrei-hasna

Copy link
Copy Markdown
Contributor

Summary — ADDITIONAL FINDING beyond the originally scoped repo list

While fixing hasna/identities, hasna/sessions, and hasna/logs, I traced their client-transport code to this shared package (@hasna/contracts, imported as @hasna/contracts/client/storage / /transport). This is the actual root cause of the *.hasna.xyz default-hostname leak for those repos (and independently duplicated in @hasna/machines, fixed separately in hasna/machines#17).

Confirmed by downloading the currently published tarball:

$ npm pack @hasna/contracts && tar xzf *.tgz
$ grep -rn "hasna.xyz" package/dist/
package/dist/client/storage.js:6153:  return `https://${name}.hasna.xyz`;
package/dist/client/transport.js:6153:  return `https://${name}.hasna.xyz`;
package/dist/index.js:7846:  return `https://${name}.hasna.xyz`;

The published @hasna/contracts@0.5.2 bundle bakes in a real internal-infra hostname template used by every downstream @hasna/* client (identities, sessions, logs, loops, and more) whenever HASNA_<APP>_API_KEY is set but no explicit HASNA_<APP>_API_URL is provided.

What changed

  • src/client/transport.ts: defaultCloudBaseUrl(name) now builds https://<app>.<domain> where <domain> comes from a new HASNA_FLEET_API_DOMAIN env var (REQUIRED for a real deployment) — new exported helper fleetApiDomain(). Absent that env var, it falls back to a neutral, non-resolving placeholder (your-deployment.example) instead of guessing a real internal hostname.
  • Doc comments in the same file neutralized to match.
  • src/client/transport.test.ts, src/client/storage.test.ts: updated fixtures/expectations to the new placeholder domain.
  • src/client/conformance.live.test.ts: this AWS-creds-gated live test against a real deployment now resolves its target host via the same defaultCloudBaseUrl() (so it still works for whoever sets HASNA_FLEET_API_DOMAIN for a real live run) instead of hardcoding the internal domain; it fails closed to test.skip (never a hard failure) when the domain isn't configured, since the existing reachable() health-check guard treats an unresolvable/placeholder host as "unreachable."
  • Rebuilt dist/ locally and confirmed zero hasna.xyz matches in the built output (not committed — dist/ is gitignored).

Why this matters

This is the actual shipped default that downstream packages (@hasna/identities, @hasna/sessions, @hasna/logs, @hasna/loops, and others) inherit via resolveClientTransport() when only an API key (no URL) is configured. Fixing only the downstream repos' own comments/tests (see hasna/identities#11, hasna/sessions PR, hasna/logs PR) does not remove this from their built/published artifacts — those packages bundle this function directly. This package needs a patched republish, and each downstream package that depends on it needs to bump to the patched @hasna/contracts version and republish too, for the fix to actually reach consumers.

Behavior change / rollout note

Any real self-hosted deployment relying on the URL-guessing default now needs HASNA_FLEET_API_DOMAIN set to the operator's real root domain (or an explicit per-app HASNA_<APP>_API_URL) — previously this was silently guessed as <app>.hasna.xyz.

Test plan

  • bun run typecheck — clean
  • bun test src/client/transport.test.ts src/client/storage.test.ts — 33/33 pass
  • bun test src/client/conformance.live.test.ts — skips cleanly (no AWS creds in this environment; confirmed skip path, not failure)
  • bun test (full suite) — 216 pass / 0 fail / 8 pre-existing skips
  • bun run build then grep -rn "hasna.xyz" dist/ — zero matches

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