@p0security/cli 0.8.3 → 0.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.
@@ -137,6 +137,13 @@ function spawnSshNode(options) {
137
137
  return __awaiter(this, void 0, void 0, function* () {
138
138
  return new Promise((resolve, reject) => {
139
139
  const provider = ssh_1.SSH_PROVIDERS[options.provider];
140
+ const attemptsRemaining = options.attemptsRemaining;
141
+ if (options.debug) {
142
+ const gerund = options.isAccessPropagationPreTest
143
+ ? "Pre-testing"
144
+ : "Trying";
145
+ (0, stdio_1.print2)(`Waiting for access to propagate. ${gerund} SSH session... (remaining attempts: ${attemptsRemaining})`);
146
+ }
140
147
  const child = spawnChildProcess(options.credential, options.command, options.args, options.stdio);
141
148
  // TODO ENG-2284 support login with Google Cloud: currently return a boolean to indicate if the exception was a Google login error.
142
149
  const { isAccessPropagated, isGoogleLoginException } = accessPropagationGuard(child, options.debug);
@@ -146,10 +153,6 @@ function spawnSshNode(options) {
146
153
  // In the case of ephemeral AccessDenied exceptions due to unpropagated
147
154
  // permissions, continually retry access until success
148
155
  if (!isAccessPropagated()) {
149
- const attemptsRemaining = options.attemptsRemaining;
150
- if (options.debug) {
151
- (0, stdio_1.print2)(`Waiting for access to propagate. Retrying SSH session... (remaining attempts: ${attemptsRemaining})`);
152
- }
153
156
  if (attemptsRemaining <= 0) {
154
157
  reject(`Access did not propagate through ${provider.friendlyName} before max retry attempts were exceeded. Please contact support@p0.dev for assistance.`);
155
158
  return;
@@ -200,7 +203,9 @@ const createCommand = (data, args, proxyCommand) => {
200
203
  ...commonArgs,
201
204
  ...(args.A ? ["-A"] : []),
202
205
  ...(args.L ? ["-L", args.L] : []),
206
+ ...(args.R ? ["-R", args.R] : []),
203
207
  ...(args.N ? ["-N"] : []),
208
+ ...(args.o ? ["-o", args.o] : []),
204
209
  `${data.linuxUserName}@${data.id}`,
205
210
  ...(args.command ? [args.command] : []),
206
211
  ...args.arguments.map((argument) =>
@@ -243,11 +248,11 @@ const preTestAccessPropagationIfNeeded = (sshProvider, request, cmdArgs, proxyCo
243
248
  }
244
249
  return null;
245
250
  });
246
- const sshOrScp = (authn, request, cmdArgs, privateKey) => __awaiter(void 0, void 0, void 0, function* () {
251
+ const sshOrScp = (args) => __awaiter(void 0, void 0, void 0, function* () {
252
+ const { authn, request, cmdArgs, privateKey, sshProvider } = args;
247
253
  if (!privateKey) {
248
254
  throw "Failed to load a private key for this request. Please contact support@p0.dev for assistance.";
249
255
  }
250
- const sshProvider = ssh_1.SSH_PROVIDERS[request.type];
251
256
  const credential = yield sshProvider.cloudProviderLogin(authn, request);
252
257
  const proxyCommand = sshProvider.proxyCommand(request);
253
258
  return (0, ssh_agent_1.withSshAgent)(cmdArgs, () => __awaiter(void 0, void 0, void 0, function* () {
@@ -8,6 +8,7 @@ This file is part of @p0security/cli
8
8
 
9
9
  You should have received a copy of the GNU General Public License along with @p0security/cli. If not, see <https://www.gnu.org/licenses/>.
10
10
  **/
11
+ import { K8sPermissionSpec } from "../plugins/kubeconfig/types";
11
12
  import { PluginSshRequest } from "./ssh";
12
13
  export declare const DONE_STATUSES: readonly ["DONE", "DONE_NOTIFIED"];
13
14
  export declare const DENIED_STATUSES: readonly ["DENIED", "DENIED_NOTIFIED"];
@@ -19,7 +20,7 @@ export declare type PermissionSpec<K extends string, P extends {
19
20
  permission: P;
20
21
  generated: G;
21
22
  };
22
- export declare type PluginRequest = PluginSshRequest;
23
+ export declare type PluginRequest = K8sPermissionSpec | PluginSshRequest;
23
24
  export declare type Request<P extends PluginRequest> = P & {
24
25
  status: string;
25
26
  principal: string;
@@ -26,6 +26,7 @@ export declare type SshProvider<PR extends PluginSshRequest = PluginSshRequest,
26
26
  toCliRequest: (request: Request<PR>, options?: {
27
27
  debug?: boolean;
28
28
  }) => Promise<Request<CliSshRequest>>;
29
+ ensureInstall: () => Promise<void>;
29
30
  /** Logs in the user to the cloud provider */
30
31
  cloudProviderLogin: (authn: Authn, request: SR) => Promise<C>;
31
32
  /** Returns the command and its arguments that are going to be injected as the ssh ProxyCommand option */
package/dist/util.d.ts CHANGED
@@ -43,3 +43,14 @@ export declare const exec: (command: string, args: string[], options?: child_pro
43
43
  export declare const throwAssertNever: (value: never) => never;
44
44
  export declare const assertNever: (value: never) => Error;
45
45
  export declare const unexpectedValueError: (value: any) => Error;
46
+ /**
47
+ * Performs a case-insensitive comparison of two strings. This uses
48
+ * `localeCompare()`, which is safer than `toLowerCase()` or `toUpperCase()` for
49
+ * non-ASCII characters and is the generally-accepted best practice. See:
50
+ * https://stackoverflow.com/a/2140723
51
+ *
52
+ * @param a The first string to compare
53
+ * @param b The second string to compare
54
+ * @returns true if the strings are equal, ignoring case
55
+ */
56
+ export declare const ciEquals: (a: string, b: string) => boolean;
package/dist/util.js CHANGED
@@ -12,7 +12,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
12
12
  return (mod && mod.__esModule) ? mod : { "default": mod };
13
13
  };
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
- exports.unexpectedValueError = exports.assertNever = exports.throwAssertNever = exports.exec = exports.timeout = exports.sleep = exports.P0_PATH = void 0;
15
+ exports.ciEquals = exports.unexpectedValueError = exports.assertNever = exports.throwAssertNever = exports.exec = exports.timeout = exports.sleep = exports.P0_PATH = void 0;
16
16
  /** Copyright © 2024-present P0 Security
17
17
 
18
18
  This file is part of @p0security/cli
@@ -95,3 +95,15 @@ const assertNever = (value) => {
95
95
  exports.assertNever = assertNever;
96
96
  const unexpectedValueError = (value) => new Error(`Unexpected code state: value ${value} had unexpected type`);
97
97
  exports.unexpectedValueError = unexpectedValueError;
98
+ /**
99
+ * Performs a case-insensitive comparison of two strings. This uses
100
+ * `localeCompare()`, which is safer than `toLowerCase()` or `toUpperCase()` for
101
+ * non-ASCII characters and is the generally-accepted best practice. See:
102
+ * https://stackoverflow.com/a/2140723
103
+ *
104
+ * @param a The first string to compare
105
+ * @param b The second string to compare
106
+ * @returns true if the strings are equal, ignoring case
107
+ */
108
+ const ciEquals = (a, b) => a.localeCompare(b, undefined, { sensitivity: "accent" }) === 0;
109
+ exports.ciEquals = ciEquals;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@p0security/cli",
3
- "version": "0.8.3",
3
+ "version": "0.10.0",
4
4
  "description": "Execute infra CLI commands with P0 grants",
5
5
  "main": "index.ts",
6
6
  "repository": {
@@ -21,9 +21,11 @@
21
21
  ],
22
22
  "dependencies": {
23
23
  "@rgrove/parse-xml": "^4.1.0",
24
+ "@types/ini": "^4.1.1",
24
25
  "dotenv": "^16.4.1",
25
26
  "express": "^4.18.2",
26
27
  "firebase": "^10.7.2",
28
+ "ini": "^4.1.3",
27
29
  "inquirer": "^9.2.15",
28
30
  "jsdom": "^24.1.1",
29
31
  "lodash": "^4.17.21",
@@ -32,6 +34,7 @@
32
34
  "pkce-challenge": "^4.1.0",
33
35
  "pluralize": "^8.0.0",
34
36
  "semver": "^7.6.0",
37
+ "tmp-promise": "^3.0.3",
35
38
  "typescript": "^4.8.4",
36
39
  "which": "^4.0.0",
37
40
  "yargs": "^17.6.0"