Skip to content

Commit 3d564d9

Browse files
authored
Merge pull request #3579 from github/mbg/start-proxy/token-check-fixes
Fix warning for PAT-like token with username
2 parents eedab83 + 137e0de commit 3d564d9

File tree

5 files changed

+247
-80
lines changed

5 files changed

+247
-80
lines changed

.vscode/tests.code-snippets

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
{
2+
// Place your codeql-action workspace snippets here. Each snippet is defined under a snippet name and has a scope, prefix, body and
3+
// description. Add comma separated ids of the languages where the snippet is applicable in the scope field. If scope
4+
// is left empty or omitted, the snippet gets applied to all languages. The prefix is what is
5+
// used to trigger the snippet and the body will be expanded and inserted. Possible variables are:
6+
// $1, $2 for tab stops, $0 for the final cursor position, and ${1:label}, ${2:another} for placeholders.
7+
// Placeholders with the same ids are connected.
8+
// Example:
9+
// "Print to console": {
10+
// "scope": "javascript,typescript",
11+
// "prefix": "log",
12+
// "body": [
13+
// "console.log('$1');",
14+
// "$2"
15+
// ],
16+
// "description": "Log output to console"
17+
// }
18+
"Test Macro": {
19+
"scope": "javascript, typescript",
20+
"prefix": "testMacro",
21+
"body": [
22+
"const ${1:nameMacro} = test.macro({",
23+
" exec: async (t: ExecutionContext<unknown>) => {},",
24+
"",
25+
" title: (providedTitle = \"\") => `${2:common title} - \\${providedTitle}`,",
26+
"});",
27+
],
28+
"description": "An Ava test macro",
29+
},
30+
}

lib/start-proxy-action.js

Lines changed: 4 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/start-proxy.test.ts

Lines changed: 142 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@ import * as startProxyExports from "./start-proxy";
1414
import { parseLanguage } from "./start-proxy";
1515
import * as statusReport from "./status-report";
1616
import {
17+
assertNotLogged,
1718
checkExpectedLogMessages,
1819
createFeatures,
19-
getRecordingLogger,
2020
makeTestToken,
2121
RecordingLogger,
2222
setupTests,
@@ -439,41 +439,155 @@ test("getCredentials accepts OIDC configurations", (t) => {
439439
t.assert(credentials.some((c) => startProxyExports.isJFrogConfig(c)));
440440
});
441441

442-
test("getCredentials logs a warning when a PAT is used without a username", async (t) => {
443-
const loggedMessages = [];
444-
const logger = getRecordingLogger(loggedMessages);
445-
const likelyWrongCredentials = toEncodedJSON([
442+
const getCredentialsMacro = test.macro({
443+
exec: async (
444+
t: ExecutionContext<unknown>,
445+
credentials: startProxyExports.RawCredential[],
446+
checkAccepted: (
447+
t: ExecutionContext<unknown>,
448+
logger: RecordingLogger,
449+
results: startProxyExports.Credential[],
450+
) => void,
451+
) => {
452+
const logger = new RecordingLogger();
453+
const credentialsString = toEncodedJSON(credentials);
454+
455+
const results = startProxyExports.getCredentials(
456+
logger,
457+
undefined,
458+
credentialsString,
459+
undefined,
460+
);
461+
462+
checkAccepted(t, logger, results);
463+
},
464+
465+
title: (providedTitle = "") => `getCredentials - ${providedTitle}`,
466+
});
467+
468+
test(
469+
"warns for PAT-like password without a username",
470+
getCredentialsMacro,
471+
[
446472
{
447473
type: "git_server",
448474
host: "https://github.com/",
449475
password: `ghp_${makeTestToken()}`,
450476
},
451-
]);
452-
453-
const results = startProxyExports.getCredentials(
454-
logger,
455-
undefined,
456-
likelyWrongCredentials,
457-
undefined,
458-
);
477+
],
478+
(t, logger, results) => {
479+
// The configurations should be accepted, despite the likely problem.
480+
t.assert(results);
481+
t.is(results.length, 1);
482+
t.is(results[0].type, "git_server");
483+
t.is(results[0].host, "https://github.com/");
484+
485+
if (startProxyExports.isUsernamePassword(results[0])) {
486+
t.assert(results[0].password?.startsWith("ghp_"));
487+
} else {
488+
t.fail("Expected a `UsernamePassword`-based credential.");
489+
}
490+
491+
// A warning should have been logged.
492+
checkExpectedLogMessages(t, logger.messages, [
493+
"using a GitHub Personal Access Token (PAT), but no username was provided",
494+
]);
495+
},
496+
);
459497

460-
// The configuration should be accepted, despite the likely problem.
461-
t.assert(results);
462-
t.is(results.length, 1);
463-
t.is(results[0].type, "git_server");
464-
t.is(results[0].host, "https://github.com/");
498+
test(
499+
"no warning for PAT-like password with a username",
500+
getCredentialsMacro,
501+
[
502+
{
503+
type: "git_server",
504+
host: "https://github.com/",
505+
username: "someone",
506+
password: `ghp_${makeTestToken()}`,
507+
},
508+
],
509+
(t, logger, results) => {
510+
// The configurations should be accepted, despite the likely problem.
511+
t.assert(results);
512+
t.is(results.length, 1);
513+
t.is(results[0].type, "git_server");
514+
t.is(results[0].host, "https://github.com/");
515+
516+
if (startProxyExports.isUsernamePassword(results[0])) {
517+
t.assert(results[0].password?.startsWith("ghp_"));
518+
} else {
519+
t.fail("Expected a `UsernamePassword`-based credential.");
520+
}
521+
522+
assertNotLogged(
523+
t,
524+
logger,
525+
"using a GitHub Personal Access Token (PAT), but no username was provided",
526+
);
527+
},
528+
);
465529

466-
if (startProxyExports.isUsernamePassword(results[0])) {
467-
t.assert(results[0].password?.startsWith("ghp_"));
468-
} else {
469-
t.fail("Expected a `UsernamePassword`-based credential.");
470-
}
530+
test(
531+
"warns for PAT-like token without a username",
532+
getCredentialsMacro,
533+
[
534+
{
535+
type: "git_server",
536+
host: "https://github.com/",
537+
token: `ghp_${makeTestToken()}`,
538+
},
539+
],
540+
(t, logger, results) => {
541+
// The configurations should be accepted, despite the likely problem.
542+
t.assert(results);
543+
t.is(results.length, 1);
544+
t.is(results[0].type, "git_server");
545+
t.is(results[0].host, "https://github.com/");
546+
547+
if (startProxyExports.isToken(results[0])) {
548+
t.assert(results[0].token?.startsWith("ghp_"));
549+
} else {
550+
t.fail("Expected a `Token`-based credential.");
551+
}
552+
553+
// A warning should have been logged.
554+
checkExpectedLogMessages(t, logger.messages, [
555+
"using a GitHub Personal Access Token (PAT), but no username was provided",
556+
]);
557+
},
558+
);
471559

472-
// A warning should have been logged.
473-
checkExpectedLogMessages(t, loggedMessages, [
474-
"using a GitHub Personal Access Token (PAT), but no username was provided",
475-
]);
476-
});
560+
test(
561+
"no warning for PAT-like token with a username",
562+
getCredentialsMacro,
563+
[
564+
{
565+
type: "git_server",
566+
host: "https://github.com/",
567+
username: "someone",
568+
token: `ghp_${makeTestToken()}`,
569+
},
570+
],
571+
(t, logger, results) => {
572+
// The configurations should be accepted, despite the likely problem.
573+
t.assert(results);
574+
t.is(results.length, 1);
575+
t.is(results[0].type, "git_server");
576+
t.is(results[0].host, "https://github.com/");
577+
578+
if (startProxyExports.isToken(results[0])) {
579+
t.assert(results[0].token?.startsWith("ghp_"));
580+
} else {
581+
t.fail("Expected a `Token`-based credential.");
582+
}
583+
584+
assertNotLogged(
585+
t,
586+
logger,
587+
"using a GitHub Personal Access Token (PAT), but no username was provided",
588+
);
589+
},
590+
);
477591

478592
test("getCredentials returns all credentials for Actions when using LANGUAGE_TO_REGISTRY_TYPE", async (t) => {
479593
const credentialsInput = toEncodedJSON(mixedCredentials);

src/start-proxy.ts

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -447,15 +447,18 @@ export function getCredentials(
447447
}
448448

449449
// If the password or token looks like a GitHub PAT, warn if no username is configured.
450-
if (
451-
((!hasUsername(authConfig) || !isDefined(authConfig.username)) &&
452-
isUsernamePassword(authConfig) &&
453-
isDefined(authConfig.password) &&
454-
isPAT(authConfig.password)) ||
455-
(isToken(authConfig) &&
456-
isDefined(authConfig.token) &&
457-
isPAT(authConfig.token))
458-
) {
450+
const noUsername =
451+
!hasUsername(authConfig) || !isDefined(authConfig.username);
452+
const passwordIsPAT =
453+
isUsernamePassword(authConfig) &&
454+
isDefined(authConfig.password) &&
455+
isPAT(authConfig.password);
456+
const tokenIsPAT =
457+
isToken(authConfig) &&
458+
isDefined(authConfig.token) &&
459+
isPAT(authConfig.token);
460+
461+
if (noUsername && (passwordIsPAT || tokenIsPAT)) {
459462
logger.warning(
460463
`A ${e.type} private registry is configured for ${e.host || e.url} using a GitHub Personal Access Token (PAT), but no username was provided. ` +
461464
`This may not work correctly. When configuring a private registry using a PAT, select "Username and password" and enter the username of the user ` +

0 commit comments

Comments
 (0)