@kanonak-protocol/cli 5.9.0 → 5.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/auth/credentialedFetch.d.ts +11 -0
- package/dist/index.js +179 -324
- package/package.json +4 -6
- package/dist/auth/enrollment/CsrBuilder.d.ts +0 -13
- package/dist/auth/enrollment/EnrollmentFlow.d.ts +0 -69
- package/dist/auth/enrollment/IssuanceClient.d.ts +0 -43
- package/dist/auth/enrollment/KeyProvider.d.ts +0 -55
- package/dist/auth/oauthHelpers.d.ts +0 -37
- package/dist/auth/publisherAuthority.d.ts +0 -38
- package/dist/auth/session/GitCredentialHelper.d.ts +0 -47
- package/dist/auth/sessionFetch.d.ts +0 -21
- package/dist/commands/connect.d.ts +0 -69
- package/dist/commands/credential.d.ts +0 -10
- package/dist/commands/credentialHelper.d.ts +0 -10
- package/dist/commands/device.d.ts +0 -9
- package/dist/commands/session.d.ts +0 -24
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kanonak-protocol/cli",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.10.0",
|
|
4
4
|
"description": "Command-line tool for the Kanonak Protocol — validate, resolve, preview, and publish semantic ontology packages.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -35,12 +35,10 @@
|
|
|
35
35
|
"semantic-web"
|
|
36
36
|
],
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@kanonak-protocol/sdk": "^5.
|
|
39
|
-
"@kanonak-protocol/types": "^5.
|
|
40
|
-
"@peculiar/x509": "^2.0.0",
|
|
38
|
+
"@kanonak-protocol/sdk": "^5.10.0",
|
|
39
|
+
"@kanonak-protocol/types": "^5.10.0",
|
|
41
40
|
"commander": "^13.0.0",
|
|
42
|
-
"js-yaml": "^4.1.1"
|
|
43
|
-
"reflect-metadata": "^0.2.2"
|
|
41
|
+
"js-yaml": "^4.1.1"
|
|
44
42
|
},
|
|
45
43
|
"devDependencies": {
|
|
46
44
|
"@types/js-yaml": "^4.0.9",
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import 'reflect-metadata';
|
|
2
|
-
import type { DeviceKey } from './KeyProvider.js';
|
|
3
|
-
export interface CsrResult {
|
|
4
|
-
/** The CSR in PEM form (`-----BEGIN CERTIFICATE REQUEST-----`). */
|
|
5
|
-
csrPem: string;
|
|
6
|
-
/** The device key's RFC 7638 thumbprint (echoes {@link DeviceKey.thumbprint}). */
|
|
7
|
-
thumbprint: string;
|
|
8
|
-
}
|
|
9
|
-
/**
|
|
10
|
-
* Build and sign a CSR for `deviceKey`. `subjectCommonName` becomes the CSR
|
|
11
|
-
* subject CN (advisory). Signed with ECDSA / SHA-256.
|
|
12
|
-
*/
|
|
13
|
-
export declare function buildCsr(deviceKey: DeviceKey, subjectCommonName: string): Promise<CsrResult>;
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
import 'reflect-metadata';
|
|
2
|
-
import type { DeviceEnrollmentRecord } from '@kanonak-protocol/sdk';
|
|
3
|
-
import type { OAuthServerMetadata } from '@kanonak-protocol/sdk';
|
|
4
|
-
import type { KeyProvider, KeyType } from './KeyProvider.js';
|
|
5
|
-
import type { FetchLike } from './IssuanceClient.js';
|
|
6
|
-
/**
|
|
7
|
-
* Device-certificate enrollment flow (issue #67, Phase 1).
|
|
8
|
-
*
|
|
9
|
-
* discover → generate a device key → build a CSR → run Authorization Code + PKCE
|
|
10
|
-
* over a 127.0.0.1 loopback redirect (RFC 7636 / 8252) with the CSR key's RFC
|
|
11
|
-
* 7638 thumbprint bound into the consent (anti-substitution) → exchange the code
|
|
12
|
-
* for a consent token → submit the CSR to the discovered native issuance
|
|
13
|
-
* endpoint → install the signed certificate in the device store.
|
|
14
|
-
*
|
|
15
|
-
* Collaborators are injectable so the flow is testable end-to-end against a
|
|
16
|
-
* mock authorization server + CA without a real browser.
|
|
17
|
-
*/
|
|
18
|
-
/** The discovery capability the flow needs (satisfied by {@link OAuthDiscovery}). */
|
|
19
|
-
export interface EnrollmentMetadataSource {
|
|
20
|
-
discover(host: string): Promise<OAuthServerMetadata | null>;
|
|
21
|
-
/** Resolve a publisher to its authority issuer URL(s) via the always-public
|
|
22
|
-
* RFC 9728 `oauth-protected-resource` document. */
|
|
23
|
-
discoverProtectedResource(host: string): Promise<string[] | null>;
|
|
24
|
-
}
|
|
25
|
-
/** Just enough of {@link CredentialStore} to reuse a stored OAuth client_id. */
|
|
26
|
-
export interface CredentialLookup {
|
|
27
|
-
getCredential(host: string): Promise<{
|
|
28
|
-
clientId?: string | null;
|
|
29
|
-
} | null>;
|
|
30
|
-
}
|
|
31
|
-
/** Just enough of {@link DeviceCertificateStore} to install the enrollment. */
|
|
32
|
-
export interface DeviceStoreLike {
|
|
33
|
-
store(host: string, record: DeviceEnrollmentRecord): Promise<void>;
|
|
34
|
-
}
|
|
35
|
-
export interface EnrollmentFlowDeps {
|
|
36
|
-
discovery?: EnrollmentMetadataSource;
|
|
37
|
-
credentialStore?: CredentialLookup;
|
|
38
|
-
deviceStore?: DeviceStoreLike;
|
|
39
|
-
keyProvider?: KeyProvider;
|
|
40
|
-
/** HTTP for DCR / token exchange / CSR issuance (injectable for tests). */
|
|
41
|
-
fetchImpl?: FetchLike;
|
|
42
|
-
/** Drives the user's consent step; defaults to opening the system browser. */
|
|
43
|
-
openBrowser?: (url: string) => void;
|
|
44
|
-
}
|
|
45
|
-
export interface EnrollOptions {
|
|
46
|
-
scopes: string[];
|
|
47
|
-
keyType?: KeyType;
|
|
48
|
-
deviceName?: string;
|
|
49
|
-
}
|
|
50
|
-
export interface EnrollmentResult {
|
|
51
|
-
success: boolean;
|
|
52
|
-
host?: string;
|
|
53
|
-
thumbprint?: string;
|
|
54
|
-
error?: string;
|
|
55
|
-
}
|
|
56
|
-
export declare class EnrollmentFlow {
|
|
57
|
-
private readonly discovery;
|
|
58
|
-
private readonly credentialStore;
|
|
59
|
-
private readonly deviceStore;
|
|
60
|
-
private readonly keyProvider;
|
|
61
|
-
private readonly fetchImpl;
|
|
62
|
-
private readonly openBrowser;
|
|
63
|
-
constructor(deps?: EnrollmentFlowDeps);
|
|
64
|
-
enroll(publisher: string, opts: EnrollOptions): Promise<EnrollmentResult>;
|
|
65
|
-
/** A stored OAuth client_id for the host, or a freshly dynamically-registered one. */
|
|
66
|
-
private resolveClientId;
|
|
67
|
-
/** Exchange an authorization code (PKCE) for the short-lived consent token. */
|
|
68
|
-
private exchangeCode;
|
|
69
|
-
}
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The "a CA signs the CSR" role of the provider-agnostic enrollment contract
|
|
3
|
-
* (issue #67), behind an interface so multiple issuance protocols sit behind one
|
|
4
|
-
* abstraction. v1 ships the {@link NativeIssuanceClient} (the OIDC-provisioner
|
|
5
|
-
* shape — submit the CSR with the consent token, the CA signs it; this is the
|
|
6
|
-
* industry best practice for consented device enrollment, per Smallstep /
|
|
7
|
-
* Tailscale / Teleport). EST (RFC 7030) and ACME (RFC 8555) adapters are later
|
|
8
|
-
* additions behind the same interface.
|
|
9
|
-
*/
|
|
10
|
-
export interface IssuanceContext {
|
|
11
|
-
/** The registry host being enrolled with. */
|
|
12
|
-
host: string;
|
|
13
|
-
/** Scopes consented for the certificate. */
|
|
14
|
-
scopes: string[];
|
|
15
|
-
/** Human-facing device label. */
|
|
16
|
-
deviceName?: string;
|
|
17
|
-
}
|
|
18
|
-
export interface IssuedCertificate {
|
|
19
|
-
/** The CA-signed leaf certificate (PEM). */
|
|
20
|
-
certificatePem: string;
|
|
21
|
-
/** The issuing chain (PEM), or '' if the server returns none. */
|
|
22
|
-
chainPem: string;
|
|
23
|
-
}
|
|
24
|
-
export interface IssuanceClient {
|
|
25
|
-
/** The issuance protocol this adapter implements, e.g. `native`. */
|
|
26
|
-
readonly protocol: string;
|
|
27
|
-
/** Submit a CSR for signing, authorized by the consent token. */
|
|
28
|
-
enroll(csrPem: string, consentToken: string, ctx: IssuanceContext): Promise<IssuedCertificate>;
|
|
29
|
-
}
|
|
30
|
-
/** A minimal fetch signature so tests can inject a localhost client. */
|
|
31
|
-
export type FetchLike = (url: string, init: RequestInit) => Promise<Response>;
|
|
32
|
-
/**
|
|
33
|
-
* Native issuance: POST the CSR + consent token (as a bearer) to the discovered
|
|
34
|
-
* enrollment endpoint; the endpoint verifies the consent (incl. the bound key
|
|
35
|
-
* thumbprint), signs the CSR, and returns `{ certificate, chain }`.
|
|
36
|
-
*/
|
|
37
|
-
export declare class NativeIssuanceClient implements IssuanceClient {
|
|
38
|
-
private readonly enrollmentEndpoint;
|
|
39
|
-
private readonly fetchImpl;
|
|
40
|
-
readonly protocol = "native";
|
|
41
|
-
constructor(enrollmentEndpoint: string, fetchImpl: FetchLike);
|
|
42
|
-
enroll(csrPem: string, consentToken: string, ctx: IssuanceContext): Promise<IssuedCertificate>;
|
|
43
|
-
}
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import { webcrypto } from 'node:crypto';
|
|
2
|
-
type JsonWebKey = webcrypto.JsonWebKey;
|
|
3
|
-
type CryptoKeyPair = webcrypto.CryptoKeyPair;
|
|
4
|
-
/**
|
|
5
|
-
* Device key custody, behind a pluggable provider (issue #67).
|
|
6
|
-
*
|
|
7
|
-
* v1 ships {@link SoftwareKeyProvider} (a WebCrypto EC P-256 key, persisted as a
|
|
8
|
-
* JWK in the OS-secure device store). The interface is shaped so a hardware
|
|
9
|
-
* provider — PKCS#11 / Secure Enclave / TPM-CNG, where the private key never
|
|
10
|
-
* leaves the token — drops in unchanged: the CSR builder and token minting only
|
|
11
|
-
* ever touch the `CryptoKey` signing handle, never raw key bytes. This is the
|
|
12
|
-
* Smallstep `step` / Teleport `tsh` key-provider pattern, scoped to Node.
|
|
13
|
-
*/
|
|
14
|
-
/** The device key types the contract recognizes. v1 implements `ec-p256`. */
|
|
15
|
-
export type KeyType = 'ec-p256';
|
|
16
|
-
/** A device-held key: a signing handle plus the public material needed for a CSR. */
|
|
17
|
-
export interface DeviceKey {
|
|
18
|
-
readonly keyType: KeyType;
|
|
19
|
-
/** The public key as a JWK (goes into the CSR / record; never secret). */
|
|
20
|
-
readonly publicKeyJwk: JsonWebKey;
|
|
21
|
-
/** RFC 7638 JWK SHA-256 thumbprint of the public key — the consent-bound identity. */
|
|
22
|
-
readonly thumbprint: string;
|
|
23
|
-
/** The key pair handle used to sign the CSR (and later mint tokens). */
|
|
24
|
-
readonly keyPair: CryptoKeyPair;
|
|
25
|
-
/**
|
|
26
|
-
* Serialize the key for the device store. Software: the private JWK.
|
|
27
|
-
* A hardware provider returns an opaque handle (no exportable key bytes).
|
|
28
|
-
*/
|
|
29
|
-
exportKeyMaterial(): Promise<Record<string, unknown>>;
|
|
30
|
-
}
|
|
31
|
-
export interface KeyProvider {
|
|
32
|
-
/** Stable id recorded with the enrollment, e.g. `software`, `pkcs11`. */
|
|
33
|
-
readonly id: string;
|
|
34
|
-
/** Generate a fresh non-shared device key of the given type. */
|
|
35
|
-
generate(keyType: KeyType): Promise<DeviceKey>;
|
|
36
|
-
/** Re-hydrate a {@link DeviceKey} from previously stored key material. */
|
|
37
|
-
importKeyMaterial(material: Record<string, unknown>, keyType: KeyType): Promise<DeviceKey>;
|
|
38
|
-
}
|
|
39
|
-
/**
|
|
40
|
-
* Software EC P-256 key provider. The private key is extractable so it can be
|
|
41
|
-
* persisted across CLI invocations (and used later to mint tokens) — the
|
|
42
|
-
* deliberate v1 tradeoff that a future hardware provider removes.
|
|
43
|
-
*/
|
|
44
|
-
export declare class SoftwareKeyProvider implements KeyProvider {
|
|
45
|
-
readonly id = "software";
|
|
46
|
-
generate(keyType: KeyType): Promise<DeviceKey>;
|
|
47
|
-
importKeyMaterial(material: Record<string, unknown>, keyType: KeyType): Promise<DeviceKey>;
|
|
48
|
-
}
|
|
49
|
-
/**
|
|
50
|
-
* RFC 7638 JWK SHA-256 thumbprint (base64url). For an EC key the canonical
|
|
51
|
-
* member set is `{crv, kty, x, y}` in lexical order — the same thumbprint DPoP's
|
|
52
|
-
* `jkt` uses, so the binding is a well-known construction.
|
|
53
|
-
*/
|
|
54
|
-
export declare function jwkThumbprint(jwk: JsonWebKey): Promise<string>;
|
|
55
|
-
export {};
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Reusable OAuth 2.0 / RFC 8252 native-app helpers: the loopback callback
|
|
3
|
-
* server, PKCE (RFC 7636) generation, the authorization-URL builder, and the
|
|
4
|
-
* system browser opener. `EnrollmentFlow` (device enrollment) builds on these so
|
|
5
|
-
* the loopback + PKCE mechanics live in exactly one place.
|
|
6
|
-
*/
|
|
7
|
-
export declare function generateCodeVerifier(): string;
|
|
8
|
-
export declare function generateCodeChallenge(verifier: string): string;
|
|
9
|
-
export declare function generateState(): string;
|
|
10
|
-
/**
|
|
11
|
-
* Build an authorization-code + PKCE-S256 request URL. `extraParams` carries
|
|
12
|
-
* flow-specific bindings — e.g. device enrollment adds the CSR key thumbprint so
|
|
13
|
-
* consent authorizes that specific key (anti-substitution).
|
|
14
|
-
*/
|
|
15
|
-
export declare function buildAuthorizationUrl(opts: {
|
|
16
|
-
endpoint: string;
|
|
17
|
-
clientId: string;
|
|
18
|
-
redirectUri: string;
|
|
19
|
-
scopes: string[];
|
|
20
|
-
state: string;
|
|
21
|
-
codeChallenge: string;
|
|
22
|
-
extraParams?: Record<string, string>;
|
|
23
|
-
}): string;
|
|
24
|
-
export interface CallbackResult {
|
|
25
|
-
code?: string;
|
|
26
|
-
state?: string;
|
|
27
|
-
error?: string;
|
|
28
|
-
}
|
|
29
|
-
export declare const CALLBACK_TIMEOUT_MS: number;
|
|
30
|
-
export declare function startCallbackServer(): Promise<{
|
|
31
|
-
redirectUri: string;
|
|
32
|
-
port: number;
|
|
33
|
-
waitForCallback: () => Promise<CallbackResult | null>;
|
|
34
|
-
close: () => void;
|
|
35
|
-
}>;
|
|
36
|
-
export declare function escapeHtml(str: string): string;
|
|
37
|
-
export declare function openBrowser(url: string): void;
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { DeviceCertificateStore } from '@kanonak-protocol/sdk';
|
|
2
|
-
/**
|
|
3
|
-
* Publisher-centric authority resolution — the ONE way every CLI command turns
|
|
4
|
-
* what the user typed into the authority that actually keys an enrollment /
|
|
5
|
-
* session.
|
|
6
|
-
*
|
|
7
|
-
* Users think in PUBLISHERS (`paul.kanonak.com`) — the domain they `connect`,
|
|
8
|
-
* `enroll`, `install` from. But device certs and the sessions minted from them
|
|
9
|
-
* are keyed by the AUTHORITY (`oauth--paul.kanonak.com`), which the user neither
|
|
10
|
-
* knows nor should have to type. The mapping is the enrollment record's
|
|
11
|
-
* `publisher` field, captured at `connect`/`enroll` time. These helpers read it
|
|
12
|
-
* (and fall back to RFC 9728 discovery) so `session login/token/logout/status`,
|
|
13
|
-
* `device show/remove`, etc. all speak the publisher domain.
|
|
14
|
-
*/
|
|
15
|
-
export interface PublisherAuthorityDeps {
|
|
16
|
-
store?: Pick<DeviceCertificateStore, 'get' | 'list'>;
|
|
17
|
-
discovery?: {
|
|
18
|
-
discoverProtectedResource(host: string): Promise<string[] | null>;
|
|
19
|
-
};
|
|
20
|
-
}
|
|
21
|
-
/**
|
|
22
|
-
* Resolve the locally-enrolled AUTHORITY for what the user typed. Order:
|
|
23
|
-
* 1. Direct — the input is already an enrolled authority key (e.g. copied
|
|
24
|
-
* from `device list`/`session status`).
|
|
25
|
-
* 2. Local mapping — an enrollment recorded this publisher; resolve with no
|
|
26
|
-
* network call (the publisher-centric fast path).
|
|
27
|
-
* 3. Network fallback — resolve the publisher to its authority via RFC 9728
|
|
28
|
-
* `oauth-protected-resource` (covers enrollments made before the publisher
|
|
29
|
-
* was recorded).
|
|
30
|
-
* Returns the authority host that has a local enrollment, or null.
|
|
31
|
-
*/
|
|
32
|
-
export declare function resolveEnrolledAuthority(input: string, deps?: PublisherAuthorityDeps): Promise<string | null>;
|
|
33
|
-
/**
|
|
34
|
-
* The publisher an enrolled authority was connected through, if it was recorded
|
|
35
|
-
* — for presenting authority-keyed state (sessions) in publisher terms. Returns
|
|
36
|
-
* undefined when the authority isn't enrolled locally or carries no publisher.
|
|
37
|
-
*/
|
|
38
|
-
export declare function publisherForAuthority(authority: string, deps?: PublisherAuthorityDeps): Promise<string | undefined>;
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import { type CredentialResolverDeps } from '@kanonak-protocol/sdk';
|
|
2
|
-
/**
|
|
3
|
-
* `kanonak` as a git credential helper (issue #72). Git invokes the helper per
|
|
4
|
-
* request; for a Kanonak-credentialed repository host it returns a freshly-valid
|
|
5
|
-
* session token, so pushes/pulls just work without static, expiring files.
|
|
6
|
-
*
|
|
7
|
-
* The actual resolution (RFC 9728 host→authority, then the authority-scoped
|
|
8
|
-
* device session) lives in the SDK's CredentialResolver — the durable primitive.
|
|
9
|
-
* This class owns only the git-specific concerns: the stdin/stdout protocol and
|
|
10
|
-
* the HTTP Basic user-id. Self-filtering: when the resolver declines (no Kanonak
|
|
11
|
-
* authority, or unenrolled), the helper emits nothing and git falls through.
|
|
12
|
-
* Identity is never inferred; the Basic user-id is an RFC 7617 carrier (the token
|
|
13
|
-
* is the credential).
|
|
14
|
-
*/
|
|
15
|
-
/** A git credential description (the key=value lines git sends on stdin). */
|
|
16
|
-
export interface GitCredential {
|
|
17
|
-
protocol?: string;
|
|
18
|
-
host?: string;
|
|
19
|
-
path?: string;
|
|
20
|
-
username?: string;
|
|
21
|
-
[key: string]: string | undefined;
|
|
22
|
-
}
|
|
23
|
-
export interface GitCredentialHelperDeps extends CredentialResolverDeps {
|
|
24
|
-
/** Carrier user-id when git's request supplies none (RFC 7617; not an identity). */
|
|
25
|
-
carrierUserId?: string;
|
|
26
|
-
}
|
|
27
|
-
export declare class GitCredentialHelper {
|
|
28
|
-
private readonly resolver;
|
|
29
|
-
private readonly carrier;
|
|
30
|
-
constructor(deps?: GitCredentialHelperDeps);
|
|
31
|
-
/**
|
|
32
|
-
* Resolve a git request to credentials, or null to DECLINE (git falls through).
|
|
33
|
-
*/
|
|
34
|
-
resolve(cred: GitCredential): Promise<{
|
|
35
|
-
username: string;
|
|
36
|
-
password: string;
|
|
37
|
-
} | null>;
|
|
38
|
-
/**
|
|
39
|
-
* Run one git credential-helper invocation: parse the request from `input`,
|
|
40
|
-
* handle the operation, and return the stdout to emit ('' = decline). Only
|
|
41
|
-
* `get` produces credentials; `store`/`erase` are no-ops because Kanonak
|
|
42
|
-
* sessions are managed by `kanonak session`, not by git.
|
|
43
|
-
*/
|
|
44
|
-
run(operation: string, input: string): Promise<string>;
|
|
45
|
-
}
|
|
46
|
-
/** Parse git's credential stdin: `key=value` lines, blank-line terminated. */
|
|
47
|
-
export declare function parseGitCredential(input: string): GitCredential;
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { CredentialResolver } from '@kanonak-protocol/sdk';
|
|
2
|
-
import type { AuthenticatedFetchFn } from '@kanonak-protocol/sdk';
|
|
3
|
-
/**
|
|
4
|
-
* A fetch transport that authenticates GATED reads with the device session.
|
|
5
|
-
*
|
|
6
|
-
* Per host, it resolves the publisher → authority → device session
|
|
7
|
-
* (CredentialResolver) and presents the session token as `Authorization: Bearer`.
|
|
8
|
-
* A public publisher resolves to no credential and the request goes out
|
|
9
|
-
* anonymously. This is what makes `install` / `connect` read a gated publisher's
|
|
10
|
-
* `kanonak.json` / `kanonak.lock` / package sources — without it, those requests
|
|
11
|
-
* hit the gate unauthenticated.
|
|
12
|
-
*
|
|
13
|
-
* Crucially it uses `redirect: 'manual'`: a gated endpoint 302-redirects an
|
|
14
|
-
* unauthenticated request (e.g. to a login), and Node's default auto-following
|
|
15
|
-
* turns that into a redirect LOOP. Not following means a gated 302 surfaces as a
|
|
16
|
-
* clean non-OK response the caller reports, instead of spinning.
|
|
17
|
-
*
|
|
18
|
-
* The resolved credential is cached per host so one `connect`/`install` doesn't
|
|
19
|
-
* re-mint a session for every package in the closure.
|
|
20
|
-
*/
|
|
21
|
-
export declare function createSessionFetch(resolver?: CredentialResolver): AuthenticatedFetchFn;
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
import type { LockFile, LockEntry, PublisherConfig, DeviceEnrollmentRecord, AuthenticatedFetchFn } from '@kanonak-protocol/sdk';
|
|
2
|
-
/** The outcome of a connect, for a host (CLI / VS Code) to report. */
|
|
3
|
-
export interface ConnectResult {
|
|
4
|
-
connected: boolean;
|
|
5
|
-
enrolled: boolean;
|
|
6
|
-
installed: number;
|
|
7
|
-
/** A failure reason, or the sentinel `'aborted'` when the user declined the install. */
|
|
8
|
-
error?: string;
|
|
9
|
-
}
|
|
10
|
-
/**
|
|
11
|
-
* Injectable collaborators so `connect` runs identically across surfaces (CLI,
|
|
12
|
-
* VS Code) and is testable without network, a device, or stdin. Every field
|
|
13
|
-
* defaults to the real implementation.
|
|
14
|
-
*/
|
|
15
|
-
export interface ConnectDeps {
|
|
16
|
-
fetchFn?: AuthenticatedFetchFn;
|
|
17
|
-
/** Resolve a publisher to its authority via RFC 9728 oauth-protected-resource. */
|
|
18
|
-
discovery?: {
|
|
19
|
-
discoverProtectedResource(host: string): Promise<string[] | null>;
|
|
20
|
-
};
|
|
21
|
-
configResolver?: {
|
|
22
|
-
getConfig(host: string): Promise<PublisherConfig>;
|
|
23
|
-
};
|
|
24
|
-
deviceStore?: {
|
|
25
|
-
get(host: string): Promise<DeviceEnrollmentRecord | null>;
|
|
26
|
-
};
|
|
27
|
-
publisherIndex?: {
|
|
28
|
-
getLock(host: string): Promise<LockFile | null>;
|
|
29
|
-
};
|
|
30
|
-
/** Run device enrollment for a publisher (resolves its authority internally). */
|
|
31
|
-
enroll?: (publisher: string) => Promise<{
|
|
32
|
-
success: boolean;
|
|
33
|
-
thumbprint?: string;
|
|
34
|
-
error?: string;
|
|
35
|
-
}>;
|
|
36
|
-
/** Fetch + verify + cache one pinned package. */
|
|
37
|
-
installEntry?: (publisher: string, packageName: string, entry: LockEntry) => Promise<void>;
|
|
38
|
-
loadLock?: () => LockFile | null;
|
|
39
|
-
saveLock?: (lock: LockFile) => void;
|
|
40
|
-
/** Ask the user to confirm the install. The host supplies its own prompt. */
|
|
41
|
-
confirm?: (question: string) => Promise<boolean>;
|
|
42
|
-
/** Progress output sink. */
|
|
43
|
-
log?: (message: string) => void;
|
|
44
|
-
}
|
|
45
|
-
/**
|
|
46
|
-
* The `connect` orchestrator core (issue #9): given a publisher domain, learn
|
|
47
|
-
* whether it is gated from the always-public RFC 9728 `oauth-protected-resource`
|
|
48
|
-
* document, enroll this device if it is gated and not already enrolled, then
|
|
49
|
-
* read the publisher's `kanonak.json` (its `featured_packages`) and install them
|
|
50
|
-
* and their pinned closures from the served `kanonak.lock`.
|
|
51
|
-
*
|
|
52
|
-
* For a gated publisher the `kanonak.json`/`kanonak.lock` are themselves behind
|
|
53
|
-
* auth, so those reads go through the device session minted from the enrolled
|
|
54
|
-
* cert. A public publisher (no `oauth-protected-resource`) never enrolls and
|
|
55
|
-
* reads everything anonymously. Pure of process/stdout concerns — returns a
|
|
56
|
-
* {@link ConnectResult} and reports via `deps.log`.
|
|
57
|
-
*/
|
|
58
|
-
export declare function connect(publisher: string, options: {
|
|
59
|
-
install?: boolean;
|
|
60
|
-
yes?: boolean;
|
|
61
|
-
}, deps?: ConnectDeps): Promise<ConnectResult>;
|
|
62
|
-
/**
|
|
63
|
-
* `kanonak connect <publisher>` — the CLI wrapper: console output, a stdin
|
|
64
|
-
* confirmation prompt, and a non-zero exit on failure.
|
|
65
|
-
*/
|
|
66
|
-
export declare function connectCommand(publisher: string, options: {
|
|
67
|
-
install?: boolean;
|
|
68
|
-
yes?: boolean;
|
|
69
|
-
}): Promise<void>;
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { Command } from 'commander';
|
|
2
|
-
/**
|
|
3
|
-
* `kanonak credential resolve <host>` — the durable host→credential primitive
|
|
4
|
-
* (issue #72), exposed for scripting. Given any registry/repo host, it resolves
|
|
5
|
-
* a freshly-valid credential (via RFC 9728 discovery + the authority-scoped
|
|
6
|
-
* device session) and prints it as JSON, or exits non-zero when Kanonak has none
|
|
7
|
-
* for that host. This is the same resolver the git credential helper uses; other
|
|
8
|
-
* tooling builds on it instead of reimplementing the auth.
|
|
9
|
-
*/
|
|
10
|
-
export declare function credentialCommand(): Command;
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { Command } from 'commander';
|
|
2
|
-
/**
|
|
3
|
-
* `kanonak credential-helper <get|store|erase>` — a git credential helper
|
|
4
|
-
* (issue #72). Git invokes it (configured via `credential.helper = !kanonak
|
|
5
|
-
* credential-helper`), passing the credential description on stdin. For a
|
|
6
|
-
* repository host that advertises a Kanonak authority (RFC 9728), it returns a
|
|
7
|
-
* freshly-refreshed session token; for any other host it prints nothing, so git
|
|
8
|
-
* falls through to its normal flow. Not meant to be run by hand.
|
|
9
|
-
*/
|
|
10
|
-
export declare function credentialHelperCommand(): Command;
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import 'reflect-metadata';
|
|
2
|
-
import { Command } from 'commander';
|
|
3
|
-
/**
|
|
4
|
-
* `kanonak device` — manage device certificates for registry authentication
|
|
5
|
-
* (issue #67). `enroll` generates a device-held key, builds a CSR, runs a
|
|
6
|
-
* consent-bound SSO flow, and installs the CA-signed certificate; `list`,
|
|
7
|
-
* `show`, and `remove` inspect and manage what was installed locally.
|
|
8
|
-
*/
|
|
9
|
-
export declare function deviceCommand(): Command;
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { Command } from 'commander';
|
|
2
|
-
/**
|
|
3
|
-
* `kanonak session` — turn an enrolled device certificate into scoped,
|
|
4
|
-
* auto-refreshing registry sessions (issue #72), for authenticating GIT to your
|
|
5
|
-
* Kanonak package repositories.
|
|
6
|
-
*
|
|
7
|
-
* Publisher-centric: every subcommand takes the PUBLISHER domain you connected
|
|
8
|
-
* to (`paul.kanonak.com`), not the OAuth authority host it resolves to. The
|
|
9
|
-
* mapping is the device enrollment captured by `connect`/`enroll`; see
|
|
10
|
-
* `resolveEnrolledAuthority`.
|
|
11
|
-
*
|
|
12
|
-
* Scope: the CLI provides dynamic GIT authentication and does not manage
|
|
13
|
-
* package-manager-native registry credentials. Kanonak packages live in Git, so
|
|
14
|
-
* the git credential helper (plus Go's `GOAUTH=git` and any `git+https`
|
|
15
|
-
* dependency fetch) is the universal mechanism; package-manager registry auth is
|
|
16
|
-
* out of scope here.
|
|
17
|
-
*
|
|
18
|
-
* `install-git-helper` wires `kanonak` in as a git credential helper; pushes and
|
|
19
|
-
* pulls then authenticate transparently (a fresh session minted from the cert per
|
|
20
|
-
* request, the repo host resolved to its authority via RFC 9728). `token` hands
|
|
21
|
-
* out a session token on demand for any other use (a git credential file, an env
|
|
22
|
-
* var, CI).
|
|
23
|
-
*/
|
|
24
|
-
export declare function sessionCommand(): Command;
|