Skip to content

Commit fa59d94

Browse files
authored
Merge branch 'main' into komal/readme-examples
2 parents cae4619 + 62a6769 commit fa59d94

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+650
-99
lines changed

COPYING.md renamed to LICENSE.md

File renamed without changes.

copyright.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/** Copyright © 2024-present P0 Security
1+
/** Copyright © 2024-present P0 Security
22
33
This file is part of @p0security/p0cli
44

package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,21 +25,25 @@
2525
"dotenv": "^16.4.1",
2626
"express": "^4.18.2",
2727
"firebase": "^10.7.2",
28+
"inquirer": "^9.2.15",
2829
"jsdom": "^24.0.0",
2930
"lodash": "^4.17.21",
3031
"open": "^8.4.0",
3132
"pkce-challenge": "^4.1.0",
3233
"pluralize": "^8.0.0",
3334
"typescript": "^4.8.4",
35+
"which": "^4.0.0",
3436
"yargs": "^17.6.0"
3537
},
3638
"devDependencies": {
3739
"@trivago/prettier-plugin-sort-imports": "^4.3.0",
3840
"@types/express": "^4.17.21",
41+
"@types/inquirer": "^9.0.7",
3942
"@types/jest": "^29.5.12",
4043
"@types/jsdom": "^21.1.6",
4144
"@types/lodash": "^4.14.202",
4245
"@types/node": "^18.11.7",
46+
"@types/which": "^3.0.3",
4347
"@types/yargs": "^17.0.13",
4448
"@typescript-eslint/eslint-plugin": "^6.4.0",
4549
"@typescript-eslint/parser": "^6.0.0",

src/commands/__tests__/__snapshots__/ls.test.ts.snap

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,21 +16,31 @@ Unknown argument: foo",
1616
}
1717
`;
1818
19-
exports[`ls when valid ls command should print list response 1`] = `
19+
exports[`ls when valid ls command should print friendly message if no items: stderr 1`] = `
2020
[
2121
[
22-
"instance-1",
22+
"No destinations",
2323
],
24+
]
25+
`;
26+
27+
exports[`ls when valid ls command should print friendly message if no items: stdout 1`] = `[]`;
28+
29+
exports[`ls when valid ls command should print list response: stderr 1`] = `
30+
[
2431
[
25-
"instance-2",
32+
"Showing destinations:",
2633
],
2734
]
2835
`;
2936
30-
exports[`ls when valid ls command should print list response 2`] = `
37+
exports[`ls when valid ls command should print list response: stdout 1`] = `
3138
[
3239
[
33-
"Showing destinations:",
40+
"instance-1",
41+
],
42+
[
43+
"instance-2",
3444
],
3545
]
3646
`;

src/commands/__tests__/login.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/** Copyright © 2024-present P0 Security
1+
/** Copyright © 2024-present P0 Security
22
33
This file is part of @p0security/p0cli
44

src/commands/__tests__/ls.test.ts

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/** Copyright © 2024-present P0 Security
1+
/** Copyright © 2024-present P0 Security
22
33
This file is part of @p0security/p0cli
44
@@ -23,22 +23,31 @@ const mockPrint1 = print1 as jest.Mock;
2323
const mockPrint2 = print2 as jest.Mock;
2424

2525
describe("ls", () => {
26+
beforeEach(() => jest.clearAllMocks());
27+
2628
describe("when valid ls command", () => {
2729
const command = "ls ssh destination";
2830

29-
beforeAll(() => {
31+
const mockItems = (items: string[]) =>
3032
mockFetchCommand.mockResolvedValue({
3133
ok: true,
3234
term: "",
3335
arg: "destination",
34-
items: ["instance-1", "instance-2"],
36+
items,
3537
});
36-
});
3738

3839
it("should print list response", async () => {
40+
mockItems(["instance-1", "instance-2"]);
41+
await lsCommand(yargs()).parse(command);
42+
expect(mockPrint1.mock.calls).toMatchSnapshot("stdout");
43+
expect(mockPrint2.mock.calls).toMatchSnapshot("stderr");
44+
});
45+
46+
it("should print friendly message if no items", async () => {
47+
mockItems([]);
3948
await lsCommand(yargs()).parse(command);
40-
expect(mockPrint1.mock.calls).toMatchSnapshot();
41-
expect(mockPrint2.mock.calls).toMatchSnapshot();
49+
expect(mockPrint1.mock.calls).toMatchSnapshot("stdout");
50+
expect(mockPrint2.mock.calls).toMatchSnapshot("stderr");
4251
});
4352
});
4453

src/commands/__tests__/request.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/** Copyright © 2024-present P0 Security
1+
/** Copyright © 2024-present P0 Security
22
33
This file is part of @p0security/p0cli
44

src/commands/__tests__/ssh.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/** Copyright © 2024-present P0 Security
1+
/** Copyright © 2024-present P0 Security
22
33
This file is part of @p0security/p0cli
44

src/commands/aws/__tests__/__input__/saml-response.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/** Copyright © 2024-present P0 Security
1+
/** Copyright © 2024-present P0 Security
22
33
This file is part of @p0security/p0cli
44

src/commands/aws/__tests__/__input__/sts-response.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/** Copyright © 2024-present P0 Security
1+
/** Copyright © 2024-present P0 Security
22
33
This file is part of @p0security/p0cli
44

src/commands/aws/__tests__/role.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/** Copyright © 2024-present P0 Security
1+
/** Copyright © 2024-present P0 Security
22
33
This file is part of @p0security/p0cli
44

src/commands/aws/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/** Copyright © 2024-present P0 Security
1+
/** Copyright © 2024-present P0 Security
22
33
This file is part of @p0security/p0cli
44

src/commands/aws/role.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/** Copyright © 2024-present P0 Security
1+
/** Copyright © 2024-present P0 Security
22
33
This file is part of @p0security/p0cli
44

src/commands/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/** Copyright © 2024-present P0 Security
1+
/** Copyright © 2024-present P0 Security
22
33
This file is part of @p0security/p0cli
44

src/commands/login.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/** Copyright © 2024-present P0 Security
1+
/** Copyright © 2024-present P0 Security
22
33
This file is part of @p0security/p0cli
44

src/commands/ls.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/** Copyright © 2024-present P0 Security
1+
/** Copyright © 2024-present P0 Security
22
33
This file is part of @p0security/p0cli
44
@@ -52,10 +52,15 @@ const ls = async (
5252
]);
5353

5454
if (data && "ok" in data && data.ok) {
55+
const label = pluralize(data.arg);
56+
if (data.items.length === 0) {
57+
print2(`No ${label}`);
58+
return;
59+
}
5560
print2(
5661
`Showing${
5762
data.isTruncated ? ` the first ${data.items.length}` : ""
58-
} ${pluralize(data.arg)}${data.term ? ` matching '${data.term}'` : ""}:`
63+
} ${label}${data.term ? ` matching '${data.term}'` : ""}:`
5964
);
6065
for (const item of data.items) {
6166
print1(item);

src/commands/request.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/** Copyright © 2024-present P0 Security
1+
/** Copyright © 2024-present P0 Security
22
33
This file is part of @p0security/p0cli
44
@@ -40,6 +40,7 @@ const isCompletedStatus = (
4040
const requestArgs = <T>(yargs: yargs.Argv<T>) =>
4141
yargs
4242
.parserConfiguration({ "unknown-options-as-args": true })
43+
.help(false) // Turn off help in order to forward the --help command to the backend so P0 can provide the available requestable resources
4344
.option("wait", {
4445
alias: "w",
4546
boolean: true,

src/commands/ssh.ts

Lines changed: 47 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/** Copyright © 2024-present P0 Security
1+
/** Copyright © 2024-present P0 Security
22
33
This file is part of @p0security/p0cli
44
@@ -27,20 +27,55 @@ import { getDoc, onSnapshot } from "firebase/firestore";
2727
import { pick } from "lodash";
2828
import yargs from "yargs";
2929

30+
export type SshCommandArgs = {
31+
instance: string;
32+
command?: string;
33+
L?: string; // port forwarding option
34+
arguments: string[];
35+
};
36+
37+
// Matches strings with the pattern "digits:digits" (e.g. 1234:5678)
38+
const LOCAL_PORT_FORWARD_PATTERN = /^\d+:\d+$/;
39+
3040
/** Maximum amount of time to wait after access is approved to wait for access
3141
* to be configured
3242
*/
3343
const GRANT_TIMEOUT_MILLIS = 60e3;
3444

3545
export const sshCommand = (yargs: yargs.Argv) =>
36-
yargs.command<{ instance: string }>(
37-
"ssh <instance>",
46+
yargs.command<SshCommandArgs>(
47+
"ssh <instance> [command [arguments..]]",
3848
"SSH into a virtual machine",
3949
(yargs) =>
40-
yargs.positional("instance", {
41-
type: "string",
42-
demandOption: true,
43-
}),
50+
yargs
51+
.positional("instance", {
52+
type: "string",
53+
demandOption: true,
54+
})
55+
.positional("command", {
56+
type: "string",
57+
describe: "Pass command to the shell",
58+
})
59+
.positional("arguments", {
60+
describe: "Command arguments",
61+
array: true,
62+
string: true,
63+
default: [] as string[],
64+
})
65+
.check((argv: yargs.ArgumentsCamelCase<SshCommandArgs>) => {
66+
if (argv.L == null) return true;
67+
68+
return (
69+
argv.L.match(LOCAL_PORT_FORWARD_PATTERN) ||
70+
"Local port forward should be in the format `local_port:remote_port`"
71+
);
72+
})
73+
.option("L", {
74+
type: "string",
75+
describe:
76+
// the order of the sockets in the address matches the ssh man page
77+
"Forward a local port to the remote host; `local_socket:remote_socket`",
78+
}),
4479
guard(ssh)
4580
);
4681

@@ -107,8 +142,7 @@ const waitForProvisioning = async <P extends PluginRequest>(
107142
* Supported SSH mechanisms:
108143
* - AWS EC2 via SSM with Okta SAML
109144
*/
110-
const ssh = async (args: yargs.ArgumentsCamelCase<{ instance: string }>) => {
111-
// Prefix is required because the backend uses it to determine that this is an AWS request
145+
const ssh = async (args: yargs.ArgumentsCamelCase<SshCommandArgs>) => {
112146
const authn = await authenticate();
113147
await validateSshInstall(authn);
114148
const response = await request(
@@ -126,6 +160,9 @@ const ssh = async (args: yargs.ArgumentsCamelCase<{ instance: string }>) => {
126160
}
127161
const { id, isPreexisting } = response;
128162
if (!isPreexisting) print2("Waiting for access to be provisioned");
163+
129164
const requestData = await waitForProvisioning<AwsSsh>(authn, id);
130-
await ssm(authn, { ...requestData, id });
165+
const requestWithId = { ...requestData, id };
166+
167+
await ssm(authn, requestWithId, args);
131168
};

src/common/auth/oidc.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/** Copyright © 2024-present P0 Security
1+
/** Copyright © 2024-present P0 Security
22
33
This file is part of @p0security/p0cli
44

src/common/auth/server.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/** Copyright © 2024-present P0 Security
1+
/** Copyright © 2024-present P0 Security
22
33
This file is part of @p0security/p0cli
44

src/common/fetch.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/** Copyright © 2024-present P0 Security
1+
/** Copyright © 2024-present P0 Security
22
33
This file is part of @p0security/p0cli
44

src/common/mime.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/** Copyright © 2024-present P0 Security
1+
/** Copyright © 2024-present P0 Security
22
33
This file is part of @p0security/p0cli
44

src/common/xml.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/** Copyright © 2024-present P0 Security
1+
/** Copyright © 2024-present P0 Security
22
33
This file is part of @p0security/p0cli
44

src/drivers/__mocks__/auth.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/** Copyright © 2024-present P0 Security
1+
/** Copyright © 2024-present P0 Security
22
33
This file is part of @p0security/p0cli
44

src/drivers/api.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/** Copyright © 2024-present P0 Security
1+
/** Copyright © 2024-present P0 Security
22
33
This file is part of @p0security/p0cli
44

src/drivers/auth.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/** Copyright © 2024-present P0 Security
1+
/** Copyright © 2024-present P0 Security
22
33
This file is part of @p0security/p0cli
44
@@ -32,11 +32,13 @@ export const cached = async <T>(
3232
loader: () => Promise<T>,
3333
options: { duration: number }
3434
): Promise<T> => {
35-
const loc = path.join(
36-
path.dirname(IDENTITY_FILE_PATH),
37-
"cache",
38-
`${name}.json`
39-
);
35+
const cachePath = path.join(path.dirname(IDENTITY_FILE_PATH), "cache");
36+
// Following lines sanitize input
37+
// nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal
38+
const loc = path.resolve(path.join(cachePath, `${name}.json`));
39+
if (!loc.startsWith(cachePath)) {
40+
throw new Error("Illegal path traversal");
41+
}
4042

4143
const loadCache = async () => {
4244
const data = await loader();

src/drivers/env.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/** Copyright © 2024-present P0 Security
1+
/** Copyright © 2024-present P0 Security
22
33
This file is part of @p0security/p0cli
44

src/drivers/firestore.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/** Copyright © 2024-present P0 Security
1+
/** Copyright © 2024-present P0 Security
22
33
This file is part of @p0security/p0cli
44

src/drivers/stdio.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/** Copyright © 2024-present P0 Security
1+
/** Copyright © 2024-present P0 Security
22
33
This file is part of @p0security/p0cli
44

src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/** Copyright © 2024-present P0 Security
1+
/** Copyright © 2024-present P0 Security
22
33
This file is part of @p0security/p0cli
44

src/plugins/__mocks__/login.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/** Copyright © 2024-present P0 Security
1+
/** Copyright © 2024-present P0 Security
22
33
This file is part of @p0security/p0cli
44

0 commit comments

Comments
 (0)