@formigio/fazemos-cli 0.10.78 → 0.10.80
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.d.ts +31 -3
- package/dist/auth.js +109 -19
- package/dist/auth.js.map +1 -1
- package/dist/authConfig.d.ts +43 -0
- package/dist/authConfig.js +54 -0
- package/dist/authConfig.js.map +1 -0
- package/dist/commands/preflight.js +14 -13
- package/dist/commands/preflight.js.map +1 -1
- package/dist/config.d.ts +53 -13
- package/dist/config.js +22 -1
- package/dist/config.js.map +1 -1
- package/dist/index.js +71 -36
- package/dist/index.js.map +1 -1
- package/dist/oidc.d.ts +111 -0
- package/dist/oidc.js +283 -0
- package/dist/oidc.js.map +1 -0
- package/dist/preflight/roster.d.ts +3 -0
- package/dist/preflight/roster.js +1 -0
- package/dist/preflight/roster.js.map +1 -1
- package/dist/preflight/row2_roleRegistration.d.ts +7 -0
- package/dist/preflight/row2_roleRegistration.js +73 -1
- package/dist/preflight/row2_roleRegistration.js.map +1 -1
- package/dist/preflight/schema.d.ts +9 -4
- package/dist/preflight/schema.js +5 -0
- package/dist/preflight/schema.js.map +1 -1
- package/package.json +1 -1
package/dist/oidc.d.ts
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OIDC redirect login for the CLI — authorization code + PKCE against the
|
|
3
|
+
* Cognito hosted UI, with the code caught on a loopback listener.
|
|
4
|
+
*
|
|
5
|
+
* ## Why this replaced email/password
|
|
6
|
+
* `USER_PASSWORD_AUTH` put the operator's password on the CLI's argv (visible
|
|
7
|
+
* in `ps` and in shell history), could never satisfy an MFA or federated-IdP
|
|
8
|
+
* challenge, and hardcoded the assumption that Cognito is the only identity
|
|
9
|
+
* source. The redirect flow moves all of that into the browser, where the
|
|
10
|
+
* hosted UI already handles it. The CLI's app client has
|
|
11
|
+
* ALLOW_USER_PASSWORD_AUTH switched off, so this is not merely the preferred
|
|
12
|
+
* path — it is the only one that works.
|
|
13
|
+
*
|
|
14
|
+
* ## Why the ports are a fixed list
|
|
15
|
+
* RFC 8252 §7.3 says a native app should bind an ephemeral loopback port and
|
|
16
|
+
* ignore the port when matching. Cognito does not implement that: it compares
|
|
17
|
+
* redirect_uri byte-for-byte against the registered CallbackURLs and supports
|
|
18
|
+
* no wildcard. So the ports have to be enumerated on both sides.
|
|
19
|
+
* LOOPBACK_PORTS below MUST stay identical to CallbackURLs on
|
|
20
|
+
* CliUserPoolClient in fazemos-api/template.yaml.
|
|
21
|
+
*
|
|
22
|
+
* ## What protects the code in transit
|
|
23
|
+
* PKCE (S256). The verifier never leaves this process, and the authorization
|
|
24
|
+
* code is worthless without it — which is what makes a plaintext loopback
|
|
25
|
+
* redirect safe, and why Cognito permits http:// only for localhost. `state`
|
|
26
|
+
* is checked on the way back to reject a callback this process did not start.
|
|
27
|
+
*/
|
|
28
|
+
/**
|
|
29
|
+
* Loopback ports the CLI will try, in order.
|
|
30
|
+
*
|
|
31
|
+
* MUST match CallbackURLs on CliUserPoolClient in fazemos-api/template.yaml.
|
|
32
|
+
* Changing this list without redeploying that stack produces a Cognito error
|
|
33
|
+
* page reading "redirect_mismatch" with no further explanation.
|
|
34
|
+
*/
|
|
35
|
+
export declare const LOOPBACK_PORTS: number[];
|
|
36
|
+
/** Path component of the redirect URI. Also fixed by the registered clients. */
|
|
37
|
+
export declare const CALLBACK_PATH = "/callback";
|
|
38
|
+
/** Scopes requested. Must be a subset of AllowedOAuthScopes on the client. */
|
|
39
|
+
export declare const SCOPES: string[];
|
|
40
|
+
export interface OidcEndpoints {
|
|
41
|
+
/** Hosted-UI origin, no trailing slash. */
|
|
42
|
+
hostedUiDomain: string;
|
|
43
|
+
clientId: string;
|
|
44
|
+
}
|
|
45
|
+
export interface TokenSet {
|
|
46
|
+
idToken: string;
|
|
47
|
+
refreshToken: string;
|
|
48
|
+
/** Seconds until the ID/access tokens expire. */
|
|
49
|
+
expiresIn: number;
|
|
50
|
+
}
|
|
51
|
+
export declare function createPkcePair(): {
|
|
52
|
+
verifier: string;
|
|
53
|
+
challenge: string;
|
|
54
|
+
};
|
|
55
|
+
export declare function createState(): string;
|
|
56
|
+
export declare function buildAuthorizeUrl(opts: {
|
|
57
|
+
endpoints: OidcEndpoints;
|
|
58
|
+
redirectUri: string;
|
|
59
|
+
state: string;
|
|
60
|
+
codeChallenge: string;
|
|
61
|
+
}): string;
|
|
62
|
+
export declare function buildLogoutUrl(endpoints: OidcEndpoints, redirectUri: string): string;
|
|
63
|
+
export interface CallbackResult {
|
|
64
|
+
code: string;
|
|
65
|
+
redirectUri: string;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Bind the first free loopback port and resolve once the browser hits
|
|
69
|
+
* CALLBACK_PATH with a matching `state`.
|
|
70
|
+
*
|
|
71
|
+
* The server is handed to `onReady` along with the redirect URI it bound, so
|
|
72
|
+
* the caller can build the authorize URL with the port that was actually
|
|
73
|
+
* acquired — the URL cannot be constructed before the bind succeeds.
|
|
74
|
+
*/
|
|
75
|
+
export declare function waitForCallback(opts: {
|
|
76
|
+
state: string;
|
|
77
|
+
timeoutMs: number;
|
|
78
|
+
onReady: (redirectUri: string) => void | Promise<void>;
|
|
79
|
+
}): Promise<CallbackResult>;
|
|
80
|
+
/**
|
|
81
|
+
* Trade the authorization code for tokens at the hosted UI's token endpoint.
|
|
82
|
+
*
|
|
83
|
+
* No client secret is sent because the CLI client is public
|
|
84
|
+
* (GenerateSecret: false) — PKCE is what authenticates the exchange.
|
|
85
|
+
*/
|
|
86
|
+
export declare function exchangeCodeForTokens(opts: {
|
|
87
|
+
endpoints: OidcEndpoints;
|
|
88
|
+
code: string;
|
|
89
|
+
redirectUri: string;
|
|
90
|
+
codeVerifier: string;
|
|
91
|
+
}): Promise<TokenSet>;
|
|
92
|
+
/**
|
|
93
|
+
* Read the `email` claim out of an ID token, for display and for the stored
|
|
94
|
+
* session label.
|
|
95
|
+
*
|
|
96
|
+
* This does NOT verify the signature, and must never be used for an
|
|
97
|
+
* authorization decision. It is safe here because the token came directly
|
|
98
|
+
* from Cognito's token endpoint over TLS moments earlier, and because the API
|
|
99
|
+
* verifies it properly on every call.
|
|
100
|
+
*/
|
|
101
|
+
export declare function readEmailClaim(idToken: string): string;
|
|
102
|
+
/**
|
|
103
|
+
* Open a URL in the user's default browser.
|
|
104
|
+
*
|
|
105
|
+
* Returns false when no opener is available (a bare Linux container, a
|
|
106
|
+
* headless CI box) so the caller can fall back to printing the URL instead of
|
|
107
|
+
* pretending it worked. stdio is ignored and the child unref'd so a browser
|
|
108
|
+
* that logs to stdout cannot corrupt the CLI's own output or hold the process
|
|
109
|
+
* open after login completes.
|
|
110
|
+
*/
|
|
111
|
+
export declare function openBrowser(url: string): boolean;
|
package/dist/oidc.js
ADDED
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OIDC redirect login for the CLI — authorization code + PKCE against the
|
|
3
|
+
* Cognito hosted UI, with the code caught on a loopback listener.
|
|
4
|
+
*
|
|
5
|
+
* ## Why this replaced email/password
|
|
6
|
+
* `USER_PASSWORD_AUTH` put the operator's password on the CLI's argv (visible
|
|
7
|
+
* in `ps` and in shell history), could never satisfy an MFA or federated-IdP
|
|
8
|
+
* challenge, and hardcoded the assumption that Cognito is the only identity
|
|
9
|
+
* source. The redirect flow moves all of that into the browser, where the
|
|
10
|
+
* hosted UI already handles it. The CLI's app client has
|
|
11
|
+
* ALLOW_USER_PASSWORD_AUTH switched off, so this is not merely the preferred
|
|
12
|
+
* path — it is the only one that works.
|
|
13
|
+
*
|
|
14
|
+
* ## Why the ports are a fixed list
|
|
15
|
+
* RFC 8252 §7.3 says a native app should bind an ephemeral loopback port and
|
|
16
|
+
* ignore the port when matching. Cognito does not implement that: it compares
|
|
17
|
+
* redirect_uri byte-for-byte against the registered CallbackURLs and supports
|
|
18
|
+
* no wildcard. So the ports have to be enumerated on both sides.
|
|
19
|
+
* LOOPBACK_PORTS below MUST stay identical to CallbackURLs on
|
|
20
|
+
* CliUserPoolClient in fazemos-api/template.yaml.
|
|
21
|
+
*
|
|
22
|
+
* ## What protects the code in transit
|
|
23
|
+
* PKCE (S256). The verifier never leaves this process, and the authorization
|
|
24
|
+
* code is worthless without it — which is what makes a plaintext loopback
|
|
25
|
+
* redirect safe, and why Cognito permits http:// only for localhost. `state`
|
|
26
|
+
* is checked on the way back to reject a callback this process did not start.
|
|
27
|
+
*/
|
|
28
|
+
import { createServer } from 'http';
|
|
29
|
+
import { createHash, randomBytes } from 'crypto';
|
|
30
|
+
import { spawn } from 'child_process';
|
|
31
|
+
/**
|
|
32
|
+
* Loopback ports the CLI will try, in order.
|
|
33
|
+
*
|
|
34
|
+
* MUST match CallbackURLs on CliUserPoolClient in fazemos-api/template.yaml.
|
|
35
|
+
* Changing this list without redeploying that stack produces a Cognito error
|
|
36
|
+
* page reading "redirect_mismatch" with no further explanation.
|
|
37
|
+
*/
|
|
38
|
+
export const LOOPBACK_PORTS = [8976, 8977, 8978, 8979, 8980];
|
|
39
|
+
/** Path component of the redirect URI. Also fixed by the registered clients. */
|
|
40
|
+
export const CALLBACK_PATH = '/callback';
|
|
41
|
+
/** Scopes requested. Must be a subset of AllowedOAuthScopes on the client. */
|
|
42
|
+
export const SCOPES = ['openid', 'email', 'profile'];
|
|
43
|
+
// ── PKCE ────────────────────────────────────────────────────
|
|
44
|
+
/**
|
|
45
|
+
* base64url per RFC 7636 §A — standard base64 with +/ swapped for -_ and the
|
|
46
|
+
* padding stripped. Node's 'base64url' encoding does exactly this, but is
|
|
47
|
+
* spelled out here because a stray '=' silently breaks the S256 comparison
|
|
48
|
+
* on Cognito's side with a generic invalid_grant.
|
|
49
|
+
*/
|
|
50
|
+
function base64url(buf) {
|
|
51
|
+
return buf.toString('base64url');
|
|
52
|
+
}
|
|
53
|
+
export function createPkcePair() {
|
|
54
|
+
// 32 random bytes → 43 base64url chars, comfortably inside RFC 7636's
|
|
55
|
+
// 43–128 character range for code_verifier.
|
|
56
|
+
const verifier = base64url(randomBytes(32));
|
|
57
|
+
const challenge = base64url(createHash('sha256').update(verifier).digest());
|
|
58
|
+
return { verifier, challenge };
|
|
59
|
+
}
|
|
60
|
+
export function createState() {
|
|
61
|
+
return base64url(randomBytes(16));
|
|
62
|
+
}
|
|
63
|
+
// ── Authorize URL ───────────────────────────────────────────
|
|
64
|
+
export function buildAuthorizeUrl(opts) {
|
|
65
|
+
const params = new URLSearchParams({
|
|
66
|
+
response_type: 'code',
|
|
67
|
+
client_id: opts.endpoints.clientId,
|
|
68
|
+
redirect_uri: opts.redirectUri,
|
|
69
|
+
scope: SCOPES.join(' '),
|
|
70
|
+
state: opts.state,
|
|
71
|
+
code_challenge: opts.codeChallenge,
|
|
72
|
+
code_challenge_method: 'S256',
|
|
73
|
+
});
|
|
74
|
+
return `${opts.endpoints.hostedUiDomain.replace(/\/$/, '')}/oauth2/authorize?${params}`;
|
|
75
|
+
}
|
|
76
|
+
export function buildLogoutUrl(endpoints, redirectUri) {
|
|
77
|
+
const params = new URLSearchParams({
|
|
78
|
+
client_id: endpoints.clientId,
|
|
79
|
+
logout_uri: redirectUri,
|
|
80
|
+
});
|
|
81
|
+
return `${endpoints.hostedUiDomain.replace(/\/$/, '')}/logout?${params}`;
|
|
82
|
+
}
|
|
83
|
+
// ── Loopback listener ───────────────────────────────────────
|
|
84
|
+
/** A browser-facing page. Deliberately dependency-free and tiny. */
|
|
85
|
+
function resultPage(title, detail) {
|
|
86
|
+
return `<!doctype html><meta charset="utf-8"><title>${title}</title>
|
|
87
|
+
<style>body{font:16px/1.6 system-ui,-apple-system,sans-serif;margin:16vh auto;max-width:34rem;padding:0 1.5rem;color:#1a1a1a}
|
|
88
|
+
h1{font-size:1.35rem;margin:0 0 .5rem}p{margin:0;color:#555}
|
|
89
|
+
@media(prefers-color-scheme:dark){body{background:#111;color:#eee}p{color:#aaa}}</style>
|
|
90
|
+
<h1>${title}</h1><p>${detail}</p>`;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Bind the first free loopback port and resolve once the browser hits
|
|
94
|
+
* CALLBACK_PATH with a matching `state`.
|
|
95
|
+
*
|
|
96
|
+
* The server is handed to `onReady` along with the redirect URI it bound, so
|
|
97
|
+
* the caller can build the authorize URL with the port that was actually
|
|
98
|
+
* acquired — the URL cannot be constructed before the bind succeeds.
|
|
99
|
+
*/
|
|
100
|
+
export function waitForCallback(opts) {
|
|
101
|
+
return new Promise((resolve, reject) => {
|
|
102
|
+
let server;
|
|
103
|
+
let settled = false;
|
|
104
|
+
let timer;
|
|
105
|
+
const finish = (err, result) => {
|
|
106
|
+
if (settled)
|
|
107
|
+
return;
|
|
108
|
+
settled = true;
|
|
109
|
+
if (timer)
|
|
110
|
+
clearTimeout(timer);
|
|
111
|
+
// close() only stops NEW connections; a keep-alive socket keeps the port
|
|
112
|
+
// bound indefinitely. Every response below sets `Connection: close` and
|
|
113
|
+
// finish() runs from the res.end() callback, so the body is already
|
|
114
|
+
// flushed by the time we tear the sockets down — without this a second
|
|
115
|
+
// login in the same process hits EADDRINUSE on every registered port.
|
|
116
|
+
server?.close();
|
|
117
|
+
server?.closeAllConnections?.();
|
|
118
|
+
if (err)
|
|
119
|
+
reject(err);
|
|
120
|
+
else
|
|
121
|
+
resolve(result);
|
|
122
|
+
};
|
|
123
|
+
/** Reply, wait for the bytes to leave, then settle. */
|
|
124
|
+
const respond = (res, status, body, contentType, done) => {
|
|
125
|
+
res.writeHead(status, { 'Content-Type': contentType, Connection: 'close' });
|
|
126
|
+
res.end(body, done);
|
|
127
|
+
};
|
|
128
|
+
const tryPort = (index) => {
|
|
129
|
+
if (index >= LOOPBACK_PORTS.length) {
|
|
130
|
+
finish(new Error(`Could not bind any of the loopback ports ${LOOPBACK_PORTS.join(', ')}. ` +
|
|
131
|
+
`Close whatever is using them and try again — these ports are fixed by ` +
|
|
132
|
+
`the redirect URIs registered with Cognito and cannot be chosen freely.`));
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
const port = LOOPBACK_PORTS[index];
|
|
136
|
+
const s = createServer((req, res) => {
|
|
137
|
+
// Only the callback path is served. Anything else (a favicon request,
|
|
138
|
+
// a stray probe) gets a 404 and is ignored, so it cannot settle the
|
|
139
|
+
// promise or be mistaken for the real redirect.
|
|
140
|
+
const url = new URL(req.url || '/', `http://localhost:${port}`);
|
|
141
|
+
if (url.pathname !== CALLBACK_PATH) {
|
|
142
|
+
// No `Connection: close` and no finish() — a stray request must not
|
|
143
|
+
// end the flow, and the listener stays up for the real redirect.
|
|
144
|
+
res.writeHead(404, { 'Content-Type': 'text/plain' });
|
|
145
|
+
res.end('Not found');
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
const error = url.searchParams.get('error');
|
|
149
|
+
const code = url.searchParams.get('code');
|
|
150
|
+
const returnedState = url.searchParams.get('state');
|
|
151
|
+
const HTML = 'text/html; charset=utf-8';
|
|
152
|
+
if (error) {
|
|
153
|
+
const description = url.searchParams.get('error_description') || '';
|
|
154
|
+
respond(res, 400, resultPage('Sign-in failed', `${error}. You can close this tab.`), HTML, () => finish(new Error(`Authorization failed: ${error}${description ? ` — ${description}` : ''}`)));
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
// A mismatched state means this callback belongs to some other flow.
|
|
158
|
+
// Reject it rather than exchanging a code we did not ask for.
|
|
159
|
+
if (returnedState !== opts.state) {
|
|
160
|
+
respond(res, 400, resultPage('Sign-in failed', 'State mismatch. You can close this tab.'), HTML, () => finish(new Error('Authorization failed: state mismatch (the callback did not come from this login attempt)')));
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
if (!code) {
|
|
164
|
+
respond(res, 400, resultPage('Sign-in failed', 'No authorization code was returned. You can close this tab.'), HTML, () => finish(new Error('Authorization failed: no code in the callback')));
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
respond(res, 200, resultPage('Signed in to Fazemos', 'You can close this tab and return to your terminal.'), HTML, () => finish(null, { code, redirectUri: `http://localhost:${port}${CALLBACK_PATH}` }));
|
|
168
|
+
});
|
|
169
|
+
s.on('error', (err) => {
|
|
170
|
+
// Port taken (or refused): fall through to the next candidate rather
|
|
171
|
+
// than failing the whole login.
|
|
172
|
+
if (err.code === 'EADDRINUSE' || err.code === 'EACCES') {
|
|
173
|
+
s.close();
|
|
174
|
+
tryPort(index + 1);
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
finish(err);
|
|
178
|
+
});
|
|
179
|
+
// 127.0.0.1, not 0.0.0.0 — the listener must not be reachable from the
|
|
180
|
+
// network. Binding the wildcard would expose the authorization code to
|
|
181
|
+
// anything that can reach this host.
|
|
182
|
+
s.listen(port, '127.0.0.1', () => {
|
|
183
|
+
server = s;
|
|
184
|
+
const addr = s.address();
|
|
185
|
+
const redirectUri = `http://localhost:${addr.port}${CALLBACK_PATH}`;
|
|
186
|
+
timer = setTimeout(() => finish(new Error('Timed out waiting for the browser redirect. Run the command again.')), opts.timeoutMs);
|
|
187
|
+
Promise.resolve(opts.onReady(redirectUri)).catch((err) => finish(err));
|
|
188
|
+
});
|
|
189
|
+
};
|
|
190
|
+
tryPort(0);
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
// ── Token exchange ──────────────────────────────────────────
|
|
194
|
+
/**
|
|
195
|
+
* Trade the authorization code for tokens at the hosted UI's token endpoint.
|
|
196
|
+
*
|
|
197
|
+
* No client secret is sent because the CLI client is public
|
|
198
|
+
* (GenerateSecret: false) — PKCE is what authenticates the exchange.
|
|
199
|
+
*/
|
|
200
|
+
export async function exchangeCodeForTokens(opts) {
|
|
201
|
+
const body = new URLSearchParams({
|
|
202
|
+
grant_type: 'authorization_code',
|
|
203
|
+
client_id: opts.endpoints.clientId,
|
|
204
|
+
code: opts.code,
|
|
205
|
+
redirect_uri: opts.redirectUri,
|
|
206
|
+
code_verifier: opts.codeVerifier,
|
|
207
|
+
});
|
|
208
|
+
const res = await fetch(`${opts.endpoints.hostedUiDomain.replace(/\/$/, '')}/oauth2/token`, {
|
|
209
|
+
method: 'POST',
|
|
210
|
+
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
211
|
+
body: body.toString(),
|
|
212
|
+
});
|
|
213
|
+
const text = await res.text();
|
|
214
|
+
if (!res.ok) {
|
|
215
|
+
// Cognito returns {"error":"invalid_grant"} with no detail on the common
|
|
216
|
+
// failures, so name the likely causes rather than echoing one word.
|
|
217
|
+
let detail = text;
|
|
218
|
+
try {
|
|
219
|
+
const parsed = JSON.parse(text);
|
|
220
|
+
detail = parsed.error_description || parsed.error || text;
|
|
221
|
+
}
|
|
222
|
+
catch { /* keep the raw body */ }
|
|
223
|
+
throw new Error(`Token exchange failed (${res.status}): ${detail}. ` +
|
|
224
|
+
`Usual causes: the code was already used, it expired (they last a few minutes), ` +
|
|
225
|
+
`or redirect_uri did not match the one sent to /oauth2/authorize.`);
|
|
226
|
+
}
|
|
227
|
+
const data = JSON.parse(text);
|
|
228
|
+
if (!data.id_token || !data.refresh_token) {
|
|
229
|
+
throw new Error('Token exchange succeeded but returned no id_token/refresh_token.');
|
|
230
|
+
}
|
|
231
|
+
return {
|
|
232
|
+
idToken: data.id_token,
|
|
233
|
+
refreshToken: data.refresh_token,
|
|
234
|
+
expiresIn: data.expires_in ?? 3600,
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
// ── ID token claims ─────────────────────────────────────────
|
|
238
|
+
/**
|
|
239
|
+
* Read the `email` claim out of an ID token, for display and for the stored
|
|
240
|
+
* session label.
|
|
241
|
+
*
|
|
242
|
+
* This does NOT verify the signature, and must never be used for an
|
|
243
|
+
* authorization decision. It is safe here because the token came directly
|
|
244
|
+
* from Cognito's token endpoint over TLS moments earlier, and because the API
|
|
245
|
+
* verifies it properly on every call.
|
|
246
|
+
*/
|
|
247
|
+
export function readEmailClaim(idToken) {
|
|
248
|
+
try {
|
|
249
|
+
const payload = idToken.split('.')[1];
|
|
250
|
+
if (!payload)
|
|
251
|
+
return 'unknown';
|
|
252
|
+
const claims = JSON.parse(Buffer.from(payload, 'base64url').toString('utf8'));
|
|
253
|
+
return claims.email || claims['cognito:username'] || 'unknown';
|
|
254
|
+
}
|
|
255
|
+
catch {
|
|
256
|
+
return 'unknown';
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
// ── Browser ─────────────────────────────────────────────────
|
|
260
|
+
/**
|
|
261
|
+
* Open a URL in the user's default browser.
|
|
262
|
+
*
|
|
263
|
+
* Returns false when no opener is available (a bare Linux container, a
|
|
264
|
+
* headless CI box) so the caller can fall back to printing the URL instead of
|
|
265
|
+
* pretending it worked. stdio is ignored and the child unref'd so a browser
|
|
266
|
+
* that logs to stdout cannot corrupt the CLI's own output or hold the process
|
|
267
|
+
* open after login completes.
|
|
268
|
+
*/
|
|
269
|
+
export function openBrowser(url) {
|
|
270
|
+
const opener = process.platform === 'darwin' ? { cmd: 'open', args: [url] }
|
|
271
|
+
: process.platform === 'win32' ? { cmd: 'cmd', args: ['/c', 'start', '', url] }
|
|
272
|
+
: { cmd: 'xdg-open', args: [url] };
|
|
273
|
+
try {
|
|
274
|
+
const child = spawn(opener.cmd, opener.args, { stdio: 'ignore', detached: true });
|
|
275
|
+
child.on('error', () => { });
|
|
276
|
+
child.unref();
|
|
277
|
+
return true;
|
|
278
|
+
}
|
|
279
|
+
catch {
|
|
280
|
+
return false;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
//# sourceMappingURL=oidc.js.map
|
package/dist/oidc.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oidc.js","sourceRoot":"","sources":["../src/oidc.ts"],"names":[],"mappings":"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"}
|
|
@@ -17,6 +17,9 @@ export interface DeclaredHereEntry {
|
|
|
17
17
|
project_slug: string;
|
|
18
18
|
role_slug: string;
|
|
19
19
|
filler: RoleEntry['filler'];
|
|
20
|
+
/** Role scope from roles.json. Passed through from RoleEntry to allow callers to check
|
|
21
|
+
* org-scoped vs project-scoped roles without re-reading the registry (BUG203). */
|
|
22
|
+
scope?: RoleEntry['scope'];
|
|
20
23
|
source_file: string;
|
|
21
24
|
}
|
|
22
25
|
export interface DeclaredCrossWorkspaceEntry {
|
package/dist/preflight/roster.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"roster.js","sourceRoot":"","sources":["../../src/preflight/roster.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,IAAI,CAAC;AACrE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"roster.js","sourceRoot":"","sources":["../../src/preflight/roster.ts"],"names":[],"mappings":"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"}
|
|
@@ -15,4 +15,11 @@ export declare function checkRow2RoleRegistration(opts: {
|
|
|
15
15
|
orgSlug: string;
|
|
16
16
|
projectSlug: string;
|
|
17
17
|
env: string;
|
|
18
|
+
/**
|
|
19
|
+
* Scope declared in roles.json for this role. When 'org', row 2 evaluates whether
|
|
20
|
+
* project_id IS NULL (correct org-scoped state) rather than comparing against a
|
|
21
|
+
* specific project. Falls back to reg.scope from the API response if omitted.
|
|
22
|
+
* (BUG203 — org-scoped roles must not FAIL row 2 with a destructive fix hint.)
|
|
23
|
+
*/
|
|
24
|
+
roleScope?: 'org' | 'project';
|
|
18
25
|
}): Promise<PreflightRow>;
|
|
@@ -27,7 +27,79 @@ export async function checkRow2RoleRegistration(opts) {
|
|
|
27
27
|
fix_command: `cd <workspace-repo> && fazemos --env ${env} roles sync --org-id ${orgSlug}${projFlag}`,
|
|
28
28
|
};
|
|
29
29
|
}
|
|
30
|
-
// ──
|
|
30
|
+
// ── Org-scoped role handling (BUG203) ──────────────────────────────────────
|
|
31
|
+
// Read scope from opts.roleScope (roles.json, preferred) or fall back to
|
|
32
|
+
// reg.scope returned by the API. For scope='org' the correct state is
|
|
33
|
+
// project_id IS NULL — do not compare against a specific project.
|
|
34
|
+
const effectiveScope = opts.roleScope ?? reg.scope;
|
|
35
|
+
if (effectiveScope === 'org') {
|
|
36
|
+
const sameOrg = reg.org_id === orgId;
|
|
37
|
+
if (!sameOrg) {
|
|
38
|
+
// Bound to a different org — configuration error, no project involved.
|
|
39
|
+
return {
|
|
40
|
+
...base,
|
|
41
|
+
status: 'fail',
|
|
42
|
+
variant: 'bound_elsewhere',
|
|
43
|
+
detail: `Row exists but bound to org=${reg.org_slug} ` +
|
|
44
|
+
`(caller wants org=${orgSlug}). Role is scope=org.`,
|
|
45
|
+
bound_to: {
|
|
46
|
+
org_slug: reg.org_slug,
|
|
47
|
+
org_id: reg.org_id,
|
|
48
|
+
project_slug: reg.project_slug,
|
|
49
|
+
project_id: reg.project_id,
|
|
50
|
+
},
|
|
51
|
+
fix_command: null,
|
|
52
|
+
fix_instruction: `role_registrations row for (workspace='${workspace}', role_slug='${roleSlug}') ` +
|
|
53
|
+
`is bound to org=${reg.org_slug}, not ${orgSlug}. ` +
|
|
54
|
+
`Org-scoped roles serve the whole org via a single binding — ` +
|
|
55
|
+
`verify your org configuration.`,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
if (reg.project_id === null) {
|
|
59
|
+
// Correct org-scoped state: bound to org, project_id IS NULL → PASS (AC1).
|
|
60
|
+
const resolverNote = candidates === null
|
|
61
|
+
? ' (resolver parity unavailable — API may be pre-r3)'
|
|
62
|
+
: candidates.length === 0
|
|
63
|
+
? ' (no resolver candidates — resolver would not resolve this role)'
|
|
64
|
+
: ` resolver deterministic: ${resolverDeterministic}`;
|
|
65
|
+
return {
|
|
66
|
+
...base,
|
|
67
|
+
status: 'pass',
|
|
68
|
+
detail: `${reg.filler_identity}, active=true, org-scoped (project_id=null) — ` +
|
|
69
|
+
`correct state for scope=org.${resolverNote}`,
|
|
70
|
+
fix_command: null,
|
|
71
|
+
...(candidates !== null && candidates.length > 0
|
|
72
|
+
? { resolver_candidates: candidates, resolver_deterministic: resolverDeterministic }
|
|
73
|
+
: {}),
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
// scope=org but project_id IS NOT NULL — binding was narrowed (AC1a / AC5).
|
|
77
|
+
// Do NOT emit set-inactive + re-run: that would migrate the binding again, not restore it.
|
|
78
|
+
return {
|
|
79
|
+
...base,
|
|
80
|
+
status: 'fail',
|
|
81
|
+
variant: 'org_scoped_project_narrowed',
|
|
82
|
+
detail: `Org-scoped role has been project-narrowed: ` +
|
|
83
|
+
`project_id=${reg.project_id} (project=${reg.project_slug ?? 'null'}) ` +
|
|
84
|
+
`but scope=org expects project_id=null. ` +
|
|
85
|
+
`Likely cause: 'roles set-inactive + re-run from project' was run before BUG203 was fixed.`,
|
|
86
|
+
bound_to: {
|
|
87
|
+
org_slug: reg.org_slug,
|
|
88
|
+
org_id: reg.org_id,
|
|
89
|
+
project_slug: reg.project_slug,
|
|
90
|
+
project_id: reg.project_id,
|
|
91
|
+
},
|
|
92
|
+
fix_command: null,
|
|
93
|
+
fix_instruction: `The binding for org-scoped role '${roleSlug}' (workspace='${workspace}') ` +
|
|
94
|
+
`has been narrowed to project=${reg.project_slug ?? reg.project_id}. ` +
|
|
95
|
+
`The schema-side fix that allows both an org binding and per-project bindings ` +
|
|
96
|
+
`is F60 Stage 3 (ROLE-REGISTRY-PROJECT-ADDRESSABILITY). ` +
|
|
97
|
+
`Do NOT run 'fazemos roles set-inactive + re-run from project' — ` +
|
|
98
|
+
`that migrates the binding again rather than restoring org scope. ` +
|
|
99
|
+
`Contact your org admin or file a follow-up referencing F60 Stage 3.`,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
// ── Bound to different (org, project) — project-scoped roles ───────────────
|
|
31
103
|
const sameOrg = reg.org_id === orgId;
|
|
32
104
|
const sameProject = projectId ? reg.project_id === projectId : true;
|
|
33
105
|
if (!sameOrg || !sameProject) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"row2_roleRegistration.js","sourceRoot":"","sources":["../../src/preflight/row2_roleRegistration.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AA2BhC,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAAC,
|
|
1
|
+
{"version":3,"file":"row2_roleRegistration.js","sourceRoot":"","sources":["../../src/preflight/row2_roleRegistration.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* F53 — Preflight verifier TypeScript types.
|
|
3
3
|
*
|
|
4
|
+
* schema_version "1.3" (bumped from 1.2 — BUG203):
|
|
5
|
+
* - Added `org_scoped_project_narrowed` Row2Variant. Introduced when a
|
|
6
|
+
* scope=org role registration has project_id IS NOT NULL (binding was narrowed
|
|
7
|
+
* by a prior operator action). Carries a F60 Stage 3 pointer, no destructive remedy.
|
|
8
|
+
* - schema_version "1.2" → "1.3" signals this addition.
|
|
4
9
|
* schema_version "1.2" (bumped from 1.1):
|
|
5
10
|
* - Added `indeterminate` status value (r3.2). Any --json consumer switching
|
|
6
11
|
* exhaustively on `status` must handle this value or may break on unknown input.
|
|
@@ -12,8 +17,8 @@
|
|
|
12
17
|
* Structural field removals or renames bump the major version.
|
|
13
18
|
*/
|
|
14
19
|
export type PreflightStatus = 'pass' | 'fail' | 'skip' | 'tooling_error' | 'xws_deferred' | 'indeterminate';
|
|
15
|
-
/** Row 2 FAIL variants (r3 penta-state). */
|
|
16
|
-
export type Row2Variant = 'no_registration' | 'bound_elsewhere' | 'resolver_ambiguous' | 'resolver_mismatch';
|
|
20
|
+
/** Row 2 FAIL variants (r3 penta-state + BUG203 org-scoped variant). */
|
|
21
|
+
export type Row2Variant = 'no_registration' | 'bound_elsewhere' | 'resolver_ambiguous' | 'resolver_mismatch' | 'org_scoped_project_narrowed';
|
|
17
22
|
export interface ResolverCandidate {
|
|
18
23
|
id: string;
|
|
19
24
|
workspace: string;
|
|
@@ -78,7 +83,7 @@ export interface PreflightSummary {
|
|
|
78
83
|
ok: boolean;
|
|
79
84
|
}
|
|
80
85
|
/**
|
|
81
|
-
* `--json` output schema (schema_version "1.
|
|
86
|
+
* `--json` output schema (schema_version "1.3").
|
|
82
87
|
*
|
|
83
88
|
* Single-project form: org + project + role + rows + summary present.
|
|
84
89
|
* Fan-out `<org>/<role>` form: roster + projects present; org + role present; project absent.
|
|
@@ -86,7 +91,7 @@ export interface PreflightSummary {
|
|
|
86
91
|
* Cross-workspace single-project: xws_deferred present; rows absent.
|
|
87
92
|
*/
|
|
88
93
|
export interface PreflightJsonOutput {
|
|
89
|
-
schema_version: '1.
|
|
94
|
+
schema_version: '1.3';
|
|
90
95
|
target: string;
|
|
91
96
|
env: string;
|
|
92
97
|
exit_code: number;
|
package/dist/preflight/schema.js
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* F53 — Preflight verifier TypeScript types.
|
|
3
3
|
*
|
|
4
|
+
* schema_version "1.3" (bumped from 1.2 — BUG203):
|
|
5
|
+
* - Added `org_scoped_project_narrowed` Row2Variant. Introduced when a
|
|
6
|
+
* scope=org role registration has project_id IS NOT NULL (binding was narrowed
|
|
7
|
+
* by a prior operator action). Carries a F60 Stage 3 pointer, no destructive remedy.
|
|
8
|
+
* - schema_version "1.2" → "1.3" signals this addition.
|
|
4
9
|
* schema_version "1.2" (bumped from 1.1):
|
|
5
10
|
* - Added `indeterminate` status value (r3.2). Any --json consumer switching
|
|
6
11
|
* exhaustively on `status` must handle this value or may break on unknown input.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/preflight/schema.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/preflight/schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AA6JH;;GAEG;AACH,MAAM,UAAU,aAAa,CAAC,IAAoB;IAChD,MAAM,MAAM,GAAG,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,aAAa,EAAE,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,aAAa,EAAE,CAAC,EAAE,CAAC;IAClG,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;QACrB,IAAI,CAAC,CAAC,MAAM,KAAK,MAAM;YAAE,MAAM,CAAC,IAAI,EAAE,CAAC;aAClC,IAAI,CAAC,CAAC,MAAM,KAAK,MAAM;YAAE,MAAM,CAAC,IAAI,EAAE,CAAC;aACvC,IAAI,CAAC,CAAC,MAAM,KAAK,MAAM;YAAE,MAAM,CAAC,IAAI,EAAE,CAAC;aACvC,IAAI,CAAC,CAAC,MAAM,KAAK,eAAe;YAAE,MAAM,CAAC,aAAa,EAAE,CAAC;aACzD,IAAI,CAAC,CAAC,MAAM,KAAK,cAAc;YAAE,MAAM,CAAC,YAAY,EAAE,CAAC;aACvD,IAAI,CAAC,CAAC,MAAM,KAAK,eAAe;YAAE,MAAM,CAAC,aAAa,EAAE,CAAC;IAChE,CAAC;IACD,OAAO,EAAE,GAAG,MAAM,EAAE,EAAE,EAAE,MAAM,CAAC,IAAI,KAAK,CAAC,IAAI,MAAM,CAAC,aAAa,KAAK,CAAC,EAAE,CAAC;AAC5E,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,IAAoB,EAAE,cAAuB;IAC3E,MAAM,OAAO,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;IACpC,IAAI,OAAO,CAAC,aAAa,GAAG,CAAC;QAAE,OAAO,CAAC,CAAC;IACxC,IAAI,OAAO,CAAC,IAAI,GAAG,CAAC;QAAE,OAAO,CAAC,CAAC;IAC/B,IAAI,cAAc,IAAI,OAAO,CAAC,YAAY,GAAG,CAAC,IAAI,OAAO,CAAC,aAAa,GAAG,CAAC;QAAE,OAAO,CAAC,CAAC;IACtF,OAAO,CAAC,CAAC;AACX,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,KAAe;IAC5C,IAAI,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC;QAAE,OAAO,CAAC,CAAC;IAChC,IAAI,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC;QAAE,OAAO,CAAC,CAAC;IAChC,IAAI,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC;QAAE,OAAO,CAAC,CAAC;IAChC,OAAO,CAAC,CAAC;AACX,CAAC"}
|