Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,14 @@ async function main(): Promise<void> {
// regardless of dotted or bracket access, so a build machine that happened to
// have it set (e.g. .env.local) would otherwise stamp one run id into the
// bundle for every user. Exclude it from the sweep so no define ever matches.
// POLYLANE_TELEMETRY_NOTICE_ACK is likewise a per-run runtime value (the
// installer sets it after printing the telemetry disclosure itself).
const DEFINE_EXCLUDE = new Set(['POLYLANE_ONBOARDING_RUN', 'POLYLANE_TELEMETRY_NOTICE_ACK']);
// The installer also sets both notice acknowledgements for its CLI child.
// They must remain runtime values so a build cannot suppress notices for
// everyone who later runs the published CLI directly.
const DEFINE_EXCLUDE = new Set([
'POLYLANE_ONBOARDING_RUN',
'POLYLANE_TELEMETRY_NOTICE_ACK',
'POLYLANE_TERMS_NOTICE_ACK',
]);
// Bake every other POLYLANE_* env var visible at build time into the bundle, so
// the produced binary works without needing those vars set at runtime.
// - Locally: comes from .env.local (gitignored — your dev domain / dev OAuth)
Expand Down
9 changes: 6 additions & 3 deletions src/commands/auth/signup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@ const TERMS_NOTICE = [
' https://polylane.com/privacy/',
].join('\n');

// The installer prints the notice before its login picker and sets this only
// for the CLI process it starts, so an email choice does not print it twice.
const showTermsNotice = (): boolean => process.env.POLYLANE_TERMS_NOTICE_ACK !== '1';

// Shown exactly once, on stderr, right after the server accepted it. Password
// reset from the console sign-in page is the way to pick a different one.
function announceGeneratedPassword(config: Config, email: string, password: string): void {
Expand Down Expand Up @@ -166,8 +170,7 @@ async function oauthSignup(config: Config, provider: 'google' | 'github'): Promi
[
`Your browser will open the Polylane signup page.`,
`Pick "${label}" there, then approve the CLI's access when asked.`,
``,
TERMS_NOTICE,
...(showTermsNotice() ? ['', TERMS_NOTICE] : []),
].join('\n'),
`Sign up with ${label}`
);
Expand Down Expand Up @@ -255,7 +258,7 @@ export async function emailSignup(config: Config, args: Record<string, unknown>)
// the console (nominal#465). No separate confirm step — that was tried in
// cli#53 and reverted. Scripted runs get it on stderr, never blocking. The
// --code completion path creates nothing, so it stays silent.
if (!codeArg) {
if (!codeArg && showTermsNotice()) {
if (isInteractive(config.nonInteractive)) note(TERMS_NOTICE);
else process.stderr.write(`\n${TERMS_NOTICE}\n\n`);
}
Expand Down
21 changes: 21 additions & 0 deletions test/signup.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ describe('auth signup terms notice', () => {
});

beforeEach(() => {
delete process.env.POLYLANE_TERMS_NOTICE_ACK;
rmSync(CONFIG_FILE, { force: true });
rmSync(CREDENTIALS_FILE, { force: true });
});
Expand Down Expand Up @@ -168,6 +169,26 @@ describe('auth signup terms notice', () => {
assert.ok(!output.includes('Continue?'));
});

it('keeps the email signup prompts but does not repeat a notice printed by the installer', async () => {
mockApi({ '/v1/auth/signup': signupResponse });
process.env.POLYLANE_TERMS_NOTICE_ACK = '1';

captureOutput();
try {
await authSignupCommand.execute(
mockConfig({ telemetry: false, nonInteractive: false }),
{} as GlobalFlags,
{ email: 'dev@acme.com' }
);
} finally {
restoreOutput();
delete process.env.POLYLANE_TERMS_NOTICE_ACK;
}

assert.ok(!output.includes(TERMS_LINE));
assert.ok(output.includes(PASSWORD_PROMPT_MARKER));
});

it('shows the notice without a gate when --password is passed interactively', async () => {
mockApi({ '/v1/auth/signup': signupResponse });

Expand Down
Loading