Skip to content

Login-minted gateway credential on the client (LLP 0061)#228

Merged
platypii merged 2 commits into
masterfrom
login-minted-gateway-client
Jul 1, 2026
Merged

Login-minted gateway credential on the client (LLP 0061)#228
platypii merged 2 commits into
masterfrom
login-minted-gateway-client

Conversation

@platypii

@platypii platypii commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Client half of login-minted gateway enrollment (LLP 0061; server half already shipped). A single hyp remote login now yields both credentials: the query session, and the gateway credential seeded where the central forward sink reads it, so a logged-in user forwards logs with no bootstrap-token distribution.

Changes

  • Capture: exchangeCode() reads gateway_jwt / gateway_expires_at / gateway_id into OidcSession.gateway and sends an advisory host label (default os.hostname(), --host <label> to override). A server that omits the fields yields no gateway; a partial set fails loudly. The gateway fields never land in the query-scoped oidc record (D1).
  • Seed: after storing the session, the login command resolves the effective layered config and seeds every @hypaware/central sink whose url shares the target's origin, at identity.persisted_path or the per-plugin default (D5). The seed is the sink's persisted identity.json pre-populated, stamped with central_url and origin: 'login' (D2/D4). A displaced identity is reported, never silent.
  • Consume: acquire() loads a login seed with no bootstrap token; the origin marker exempts it from the token-fingerprint mint check while the central_url re-point guards apply unchanged, and a re-point refusal now advises re-login instead of hyp join (D3/D4). Refresh preserves the provenance.
  • Docs: LLP 0061 marked Implemented, with the persisted-path and multi-target open questions resolved.

Testing

  • New unit tests: gateway capture/host in exchangeCode, seed writer + origin-aware guards in the central identity client, and command-level seeding through the real config resolution (default and custom paths, origin matching, replacement notes, failure reporting).
  • remote_oidc_login smoke extended: the stub server mints a gateway on login; the flow seeds it and proves the sink's IdentityClient loads it without a bootstrap token.
  • npm test (1796 pass), npm run typecheck, npm run lint all clean.

hyp remote login now captures the gateway_jwt/gateway_expires_at/gateway_id
fields a login-configured server returns on the authorization_code grant,
sends an advisory host label (default os.hostname(), --host to override),
and seeds the credential into every @hypaware/central sink whose url shares
the target's origin, at the sink's persisted identity path. The sink's
acquire() loads a login seed with no bootstrap token; an origin: 'login'
marker keeps the re-enrollment guard from reading the missing token
fingerprint as a mint mismatch, while the central_url re-point guards apply
unchanged. Covered by unit tests and the extended remote_oidc_login smoke.
@platypii

platypii commented Jul 1, 2026

Copy link
Copy Markdown
Contributor Author

Review: Login-minted gateway credential on the client (LLP 0061)

Overall this is a clean, well-documented change: the login/seed/consume split matches LLP 0061, the persisted-path and origin-matching derivations line up with what the central sink actually uses, and the guard behavior is well covered by tests. npm test (1796 pass) and the extended remote_oidc_login smoke both pass locally.

Blocking: CI failure is real, caused by this PR

The red CI checks are a genuine defect, not flakiness. All three jobs (lint, test, typecheck) fail in the npm i step, which runs the prepare script -> npm run build:types (tsc -p tsconfig.build.json, rootDir: src):

src/core/remote/gateway_seed.js(5,32): error TS6059: File
'.../hypaware-core/plugins-workspace/central/src/identity_client.js'
is not under 'rootDir' '.../src'.

src/core/remote/gateway_seed.js:5 is a runtime value import reaching out of src/ into hypaware-core/:

import { writeLoginSeed } from '../../../hypaware-core/plugins-workspace/central/src/identity_client.js'

The declaration build compiles only src/ (rootDir: src) and refuses to pull a source file from outside that root into the compilation. This is why the author's local npm test / npm run typecheck / npm run lint were green (none of them run build:types) while CI, which triggers it via prepare on npm i, is red. It reproduces locally with npm run build:types.

Note the repo convention (CLAUDE.md) that hypaware-core/... specifiers only need the .js extension applies to type imports (@import), which are erased. This is a value import, so it actually pulls the file into the program. The fix needs to get writeLoginSeed to the caller without a cross-root value import (e.g. move the seed-writer into src/, or invert the dependency so src doesn't import a hypaware-core value at build-declaration time). Worth confirming how existing runtime boundaries between src and hypaware-core are crossed elsewhere.

Non-blocking: seeding can target an uninstalled central sink

seedLoginGateway resolves the effective config without the plugin catalog, so it will seed any config block whose plugin is @hypaware/central and whose url origin matches, even if that plugin isn't installed/active. The result is an identity.json written where nothing reads it. Harmless, but if you want the seed set to match what the daemon would actually run, gating on installed plugins would tighten it. Optional.

Everything else (error reporting on partial gateway_*, the origin-exemption guard, replacement notes, the no-em-dash rule) looks correct.

The published declaration build (`npm run build:types`, `rootDir: src`)
compiled `src/core/remote/gateway_seed.js`, which imported `writeLoginSeed`
as a value from `hypaware-core/.../central/src/identity_client.js`. A value
import pulls that out-of-root file into the program, so tsc failed with
TS6059 and CI's `npm i` -> `prepare` -> `build:types` went red (local
`npm test` / typecheck / lint never run build:types, so it looked clean).

Move the seed writer to `src/core/remote/gateway_seed.js`, the login/seed
producer side of the package boundary. The sink (`hypaware-core`) only reads
and refreshes the persisted identity; the file format is the contract between
the two halves and the sink validates it on read. `src` no longer imports a
sink value; the only cross-boundary reference left is the type-only
`PersistedIdentity` import, which is erased. LLP 0061 D5 and the @ref move
with the writer.
@platypii platypii merged commit 1f473d2 into master Jul 1, 2026
6 checks passed
@platypii platypii deleted the login-minted-gateway-client branch July 1, 2026 23:45
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