@catladder/cli 0.0.0-next-78d43d4a → 0.0.0-next-dbb75f51

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.
Files changed (75) hide show
  1. package/CONTRIBUTING.md +1 -1
  2. package/README.md +2 -2
  3. package/dist/apps/cli/src/catci.js +2 -2
  4. package/dist/apps/cli/src/catci.js.map +1 -1
  5. package/dist/apps/cli/src/commands/project/commandGitlabCi.js +2 -1
  6. package/dist/apps/cli/src/commands/project/commandGitlabCi.js.map +1 -1
  7. package/dist/apps/cli/src/commands/security/commandSecurityAuditCiJob.js +2 -2
  8. package/dist/apps/cli/src/commands/security/commandSecurityAuditCiJob.js.map +1 -1
  9. package/dist/apps/cli/src/commands/security/commandSecurityAuditCreate.js +2 -2
  10. package/dist/apps/cli/src/commands/security/commandSecurityAuditCreate.js.map +1 -1
  11. package/dist/apps/cli/src/publish/npmPublishJob.js +22 -5
  12. package/dist/apps/cli/src/publish/npmPublishJob.js.map +1 -1
  13. package/dist/apps/cli/src/security/topics.json +15 -15
  14. package/dist/apps/cli/src/utils/gitlabHost.d.ts +14 -0
  15. package/dist/apps/cli/src/utils/gitlabHost.js +27 -0
  16. package/dist/apps/cli/src/utils/gitlabHost.js.map +1 -0
  17. package/dist/bundles/catci/index.js +10 -4
  18. package/dist/bundles/catenv/index.js +137 -36
  19. package/dist/bundles/cli/index.js +178 -42
  20. package/dist/bundles/runner-images/kubernetes/helm-charts/the-panter-chart/README.md +2 -2
  21. package/dist/bundles/runner-images/kubernetes/helm-charts/the-panter-chart/templates/_helpers.tpl +0 -10
  22. package/dist/bundles/runner-images/kubernetes/helm-charts/the-panter-chart/templates/app.ingress.yaml +0 -5
  23. package/dist/bundles/runner-images/kubernetes/helm-charts/the-panter-chart/values.yaml +0 -1
  24. package/dist/bundles/runner-images/npm-publish/Dockerfile +12 -0
  25. package/dist/bundles/runner-images/semantic-release/scripts/semanticRelease +4 -3
  26. package/dist/bundles/skills/catladder-config/SKILL.md +1 -1
  27. package/dist/bundles/skills/catladder-deploys/references/deploy-types.md +3 -2
  28. package/dist/packages/pipeline/src/backends/github/createGithubJobs.js +70 -24
  29. package/dist/packages/pipeline/src/backends/github/createGithubJobs.js.map +1 -1
  30. package/dist/packages/pipeline/src/backends/gitlab/GitlabBackend.js +11 -1
  31. package/dist/packages/pipeline/src/backends/gitlab/GitlabBackend.js.map +1 -1
  32. package/dist/packages/pipeline/src/backends/gitlab/createGitlabJobs.js +5 -1
  33. package/dist/packages/pipeline/src/backends/gitlab/createGitlabJobs.js.map +1 -1
  34. package/dist/packages/pipeline/src/backends/index.d.ts +6 -0
  35. package/dist/packages/pipeline/src/backends/index.js +9 -2
  36. package/dist/packages/pipeline/src/backends/index.js.map +1 -1
  37. package/dist/packages/pipeline/src/context/getEnvironmentVariables.d.ts +1 -1
  38. package/dist/packages/pipeline/src/customImages/shippedImages.js +1 -0
  39. package/dist/packages/pipeline/src/customImages/shippedImages.js.map +1 -1
  40. package/dist/packages/pipeline/src/deploy/base/deploy.js +1 -0
  41. package/dist/packages/pipeline/src/deploy/base/deploy.js.map +1 -1
  42. package/dist/packages/pipeline/src/deploy/npmPackage/deployJob.js +6 -1
  43. package/dist/packages/pipeline/src/deploy/npmPackage/deployJob.js.map +1 -1
  44. package/dist/packages/pipeline/src/deploy/pages/deployJob.js +16 -5
  45. package/dist/packages/pipeline/src/deploy/pages/deployJob.js.map +1 -1
  46. package/dist/packages/pipeline/src/pipeline/generatePipelineFiles.js +10 -0
  47. package/dist/packages/pipeline/src/pipeline/generatePipelineFiles.js.map +1 -1
  48. package/dist/packages/pipeline/src/runner/index.d.ts +1 -1
  49. package/dist/packages/pipeline/src/runner/index.js.map +1 -1
  50. package/dist/packages/pipeline/src/types/config.d.ts +4 -4
  51. package/dist/packages/pipeline/src/types/hooks.d.ts +1 -1
  52. package/dist/packages/pipeline/src/types/jobDefinition.d.ts +1 -1
  53. package/dist/packages/pipeline/src/types/jobs.d.ts +9 -0
  54. package/dist/packages/pipeline/src/types/jobs.js.map +1 -1
  55. package/dist/packages/pipeline/src/utils/writeFiles.d.ts +6 -0
  56. package/dist/packages/pipeline/src/utils/writeFiles.js +8 -2
  57. package/dist/packages/pipeline/src/utils/writeFiles.js.map +1 -1
  58. package/dist/runner-images/kubernetes/helm-charts/the-panter-chart/README.md +2 -2
  59. package/dist/runner-images/kubernetes/helm-charts/the-panter-chart/templates/_helpers.tpl +0 -10
  60. package/dist/runner-images/kubernetes/helm-charts/the-panter-chart/templates/app.ingress.yaml +0 -5
  61. package/dist/runner-images/kubernetes/helm-charts/the-panter-chart/values.yaml +0 -1
  62. package/dist/runner-images/npm-publish/Dockerfile +12 -0
  63. package/dist/runner-images/semantic-release/scripts/semanticRelease +4 -3
  64. package/dist/skills/catladder-config/SKILL.md +1 -1
  65. package/dist/skills/catladder-deploys/references/deploy-types.md +3 -2
  66. package/dist/tsconfig.tsbuildinfo +1 -1
  67. package/includes/envrc +1 -1
  68. package/package.json +5 -5
  69. package/src/catci.ts +2 -3
  70. package/src/commands/project/commandGitlabCi.ts +2 -1
  71. package/src/commands/security/commandSecurityAuditCiJob.ts +2 -3
  72. package/src/commands/security/commandSecurityAuditCreate.ts +2 -3
  73. package/src/publish/npmPublishJob.ts +32 -6
  74. package/src/security/topics.json +15 -15
  75. package/src/utils/gitlabHost.ts +23 -0
package/includes/envrc CHANGED
@@ -1,5 +1,5 @@
1
1
  # adjust this file to your needs
2
- # find a current recommended version here: https://git.panter.ch/panter/catladder2/-/blob/master/includes/envrc
2
+ # find a current recommended version here: https://github.com/panter/catladder/blob/main/apps/cli/includes/envrc
3
3
 
4
4
  # if catladder is available, invoke that
5
5
  if hash catladder 2>/dev/null; then
package/package.json CHANGED
@@ -2,12 +2,12 @@
2
2
  "name": "@catladder/cli",
3
3
  "description": "Panter cli tool for cloud CI/CD and DevOps",
4
4
  "author": "Marco Wettstein <maw@panter.ch>",
5
- "homepage": "https://catladder.git.panter.biz/catladder/docs",
6
- "bugs": "https://git.panter.ch/catladder/catladder/issues",
7
- "readme": "https://git.panter.ch/catladder/catladder/-/blob/main/cli/README.md",
5
+ "homepage": "https://panter.github.io/catladder/docs",
6
+ "bugs": "https://github.com/panter/catladder/issues",
7
+ "readme": "https://github.com/panter/catladder/blob/main/apps/cli/README.md",
8
8
  "repository": {
9
9
  "type": "git",
10
- "url": "git+https://git.panter.ch/catladder/catladder.git",
10
+ "url": "git+https://github.com/panter/catladder.git",
11
11
  "directory": "apps/cli"
12
12
  },
13
13
  "keywords": [
@@ -53,7 +53,7 @@
53
53
  }
54
54
  ],
55
55
  "license": "MIT",
56
- "version": "0.0.0-next-78d43d4a",
56
+ "version": "0.0.0-next-dbb75f51",
57
57
  "scripts": {
58
58
  "lint": "eslint \"src/**/*.ts\"",
59
59
  "lint:fix": "eslint \"src/**/*.ts\" --fix",
package/src/catci.ts CHANGED
@@ -29,8 +29,7 @@ import {
29
29
  githubQueuedGuardJob,
30
30
  } from "./release/githubQueuedRelease";
31
31
  import { npmPublishJob, parseNpmPublishArgs } from "./publish/npmPublishJob";
32
-
33
- const GITLAB_HOST = "https://git.panter.ch";
32
+ import { getGitlabHostUrl } from "./utils/gitlabHost";
34
33
 
35
34
  const USAGE = `catci — catladder CI companion
36
35
 
@@ -129,7 +128,7 @@ const securityAuditCiJob = async (
129
128
  console.log("could not evaluate security audit document");
130
129
  console.log("creating new merge request with security audit template...");
131
130
 
132
- const api = new Gitlab({ host: GITLAB_HOST, token });
131
+ const api = new Gitlab({ host: await getGitlabHostUrl(), token });
133
132
  const mr = await createSecurityAuditMergeRequest({
134
133
  api,
135
134
  mainBranch,
@@ -2,6 +2,7 @@ import { exec } from "child-process-promise";
2
2
  import { last } from "lodash-es";
3
3
  import open from "open";
4
4
  import { defineCommand } from "../../core/defineCommand";
5
+ import { getGitlabHostUrl } from "../../utils/gitlabHost";
5
6
  import {
6
7
  doGitlabRequest,
7
8
  getGitlabToken,
@@ -99,7 +100,7 @@ export const commandCiJobLog = defineCommand({
99
100
  const trace = await exec(
100
101
  `curl -s --header "PRIVATE-TOKEN: ${await getGitlabToken(
101
102
  ctx,
102
- )}" "https://git.panter.ch/api/v4/projects/${projectId}/jobs/${id}/trace"`,
103
+ )}" "${await getGitlabHostUrl()}/api/v4/projects/${projectId}/jobs/${id}/trace"`,
103
104
  );
104
105
 
105
106
  const job = await doGitlabRequest(
@@ -8,8 +8,7 @@ import {
8
8
  createSecurityAuditMergeRequest,
9
9
  SECURITY_AUDIT_FILE_NAME,
10
10
  } from "../../security/createSecurityAuditMergeRequest";
11
-
12
- const GITLAB_HOST = "https://git.panter.ch";
11
+ import { getGitlabHostUrl } from "../../utils/gitlabHost";
13
12
 
14
13
  export const commandSecurityAuditCiJob = defineCommand({
15
14
  name: "security audit ci-job",
@@ -52,7 +51,7 @@ export const commandSecurityAuditCiJob = defineCommand({
52
51
  const projectId = await ctx.get("projectId");
53
52
  const userId = await ctx.get("userId");
54
53
 
55
- const api = new Gitlab({ host: GITLAB_HOST, token });
54
+ const api = new Gitlab({ host: await getGitlabHostUrl(), token });
56
55
 
57
56
  const mr = await createSecurityAuditMergeRequest({
58
57
  api,
@@ -1,8 +1,7 @@
1
1
  import { defineCommand } from "../../core/defineCommand";
2
2
  import { Gitlab } from "@gitbeaker/rest";
3
3
  import { createSecurityAuditMergeRequest } from "../../security/createSecurityAuditMergeRequest";
4
-
5
- const GITLAB_HOST = "https://git.panter.ch";
4
+ import { getGitlabHostUrl } from "../../utils/gitlabHost";
6
5
 
7
6
  export const commandSecurityAuditCreate = defineCommand({
8
7
  name: "security audit create",
@@ -36,7 +35,7 @@ export const commandSecurityAuditCreate = defineCommand({
36
35
  const projectId = await ctx.get("projectId");
37
36
  const userId = await ctx.get("userId");
38
37
 
39
- const api = new Gitlab({ host: GITLAB_HOST, token });
38
+ const api = new Gitlab({ host: await getGitlabHostUrl(), token });
40
39
 
41
40
  const result = await createSecurityAuditMergeRequest({
42
41
  api,
@@ -74,12 +74,29 @@ const writeNpmrc = async (dir: string, registry: string) => {
74
74
  return npmrcPath;
75
75
  };
76
76
 
77
- const npmPublish = (dir: string, npmrcPath: string, args: string[]) =>
77
+ /**
78
+ * whether the CI job can mint an OIDC token for npm trusted publishing.
79
+ * github actions exposes these two only when the job declares
80
+ * `permissions: id-token: write` (catladder sets it via the job's
81
+ * `idToken` flag).
82
+ */
83
+ const hasOidcCredentials = () =>
84
+ !!process.env.ACTIONS_ID_TOKEN_REQUEST_URL &&
85
+ !!process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN;
86
+
87
+ const npmPublish = (
88
+ dir: string,
89
+ npmrcPath: string | undefined,
90
+ args: string[],
91
+ ) =>
78
92
  new Promise<void>((resolvePromise, reject) => {
79
93
  const child = spawn("npm", ["publish", ...args], {
80
94
  cwd: dir,
81
95
  stdio: "inherit",
82
- env: { ...process.env, NPM_CONFIG_USERCONFIG: npmrcPath },
96
+ env: {
97
+ ...process.env,
98
+ ...(npmrcPath ? { NPM_CONFIG_USERCONFIG: npmrcPath } : {}),
99
+ },
83
100
  });
84
101
  child.on("error", reject);
85
102
  child.on("exit", (code) =>
@@ -90,9 +107,10 @@ const npmPublish = (dir: string, npmrcPath: string, args: string[]) =>
90
107
  });
91
108
 
92
109
  export const npmPublishJob = async (options: NpmPublishJobOptions) => {
93
- if (!process.env.NPM_TOKEN) {
110
+ const oidc = hasOidcCredentials();
111
+ if (!oidc && !process.env.NPM_TOKEN) {
94
112
  throw new Error(
95
- "NPM_TOKEN is not set — configure it as a catladder secret for this component",
113
+ "NPM_TOKEN is not set — configure it as a catladder secret for this component, or publish from a workflow registered as a trusted publisher on npm",
96
114
  );
97
115
  }
98
116
  const registry = options.registry ?? DEFAULT_NPM_REGISTRY;
@@ -103,10 +121,18 @@ export const npmPublishJob = async (options: NpmPublishJobOptions) => {
103
121
  });
104
122
 
105
123
  const name = await setPackageVersion(options.dir, plan.version);
106
- const npmrcPath = await writeNpmrc(options.dir, registry);
124
+ // with OIDC available npm mints its own short-lived credentials, and
125
+ // an .npmrc referencing an unset ${NPM_TOKEN} would only get in the
126
+ // way. A token, when present, still wins as the fallback.
127
+ const npmrcPath =
128
+ oidc && !process.env.NPM_TOKEN
129
+ ? undefined
130
+ : await writeNpmrc(options.dir, registry);
107
131
 
108
132
  console.log(
109
- `publishing ${name}@${plan.version} (dist-tag ${plan.distTag}) to ${registry}`,
133
+ `publishing ${name}@${plan.version} (dist-tag ${plan.distTag}) to ${registry}${
134
+ npmrcPath ? "" : " via trusted publishing (OIDC)"
135
+ }`,
110
136
  );
111
137
  await npmPublish(options.dir, npmrcPath, [
112
138
  "--tag",
@@ -17,67 +17,67 @@
17
17
  {
18
18
  "description": "No sensitive information (passwords, keys, user data, ...) is logged or traced",
19
19
  "responsibles": 1,
20
- "more": "[Logging guide](https://www.notion.so/panterch/Long-story-logging-022722bb878f4724ae5b49e17667b630?pvs=4#9e5a36b7158a4953b73ec6a345bd8989), [Tracing guide](https://www.notion.so/panterch/Long-story-tracing-d8a9ec1ac2ff4fa78cefa8991233224e?pvs=4#535121b5bf9741fbaf8654b4b64d879d)"
20
+ "more": ""
21
21
  },
22
22
  {
23
23
  "description": "Passwords are stored hashed with salt and salt is not stored in the repository",
24
24
  "responsibles": 1,
25
- "more": "[guide](https://git.panter.ch/panter/security-guide/-/blob/main/docs/audit/hash.md)"
25
+ "more": ""
26
26
  },
27
27
  {
28
28
  "description": "Input that ends up in DOM is properly sanitized",
29
29
  "responsibles": 1,
30
- "more": "[guide](https://git.panter.ch/panter/security-guide/-/blob/main/docs/audit/xss.md)"
30
+ "more": ""
31
31
  },
32
32
  {
33
33
  "description": "All user inputs have reasonable validations",
34
34
  "responsibles": 1,
35
- "more": "[guide](https://git.panter.ch/panter/security-guide/-/blob/main/docs/audit/validation.md)"
35
+ "more": ""
36
36
  },
37
37
  {
38
38
  "description": "The app is not using cookies",
39
39
  "responsibles": 1,
40
- "more": "[guide](https://git.panter.ch/panter/security-guide/-/blob/main/docs/audit/cookies.md)"
40
+ "more": ""
41
41
  },
42
42
  {
43
43
  "description": "The app is using cookies and cookies are properly configured",
44
44
  "responsibles": 1,
45
- "more": "[guide](https://git.panter.ch/panter/security-guide/-/blob/main/docs/audit/cookies.md)"
45
+ "more": ""
46
46
  },
47
47
  {
48
48
  "description": "The app uses JWT with a secret and the secret is not stored in the repository",
49
49
  "responsibles": 1,
50
- "more": "[guide](https://git.panter.ch/panter/security-guide/-/blob/main/docs/audit/cookies.md)"
50
+ "more": ""
51
51
  },
52
52
  {
53
53
  "description": "Authorization and user roles (RBAC) were reviewed thoroughly",
54
54
  "responsibles": 2,
55
- "more": "[guide](https://git.panter.ch/panter/security-guide/-/blob/main/docs/audit/authorization.md)"
55
+ "more": ""
56
56
  },
57
57
  {
58
58
  "description": "CORS headers do not use `*`",
59
59
  "responsibles": 1,
60
- "more": "[guide](https://git.panter.ch/panter/security-guide/-/blob/main/docs/audit/cors.md)"
60
+ "more": ""
61
61
  },
62
62
  {
63
63
  "description": "CSP headers are properly configured (no `unsafe-inline` or `unsafe-eval`)",
64
64
  "responsibles": 1,
65
- "more": "[guide](https://git.panter.ch/panter/security-guide/-/blob/main/docs/audit/csp.md)"
65
+ "more": ""
66
66
  },
67
67
  {
68
68
  "description": "DoS defense mechanism is implemented",
69
69
  "responsibles": 1,
70
- "more": "[guide](https://git.panter.ch/panter/security-guide/-/blob/main/docs/audit/dos.md)"
70
+ "more": ""
71
71
  },
72
72
  {
73
73
  "description": "YAML/XML parsing is not used or used YAML/XML parsers have disabled DTD",
74
74
  "responsibles": 1,
75
- "more": "[guide](https://git.panter.ch/panter/security-guide/-/blob/main/docs/audit/dos.md)"
75
+ "more": ""
76
76
  },
77
77
  {
78
78
  "description": "The app implements CSRF prevention",
79
79
  "responsibles": 1,
80
- "more": "[guide](https://git.panter.ch/panter/security-guide/-/blob/main/docs/audit/csrf.md)"
80
+ "more": ""
81
81
  },
82
82
  {
83
83
  "description": "The app has a rate limitter",
@@ -87,12 +87,12 @@
87
87
  {
88
88
  "description": "The app has disabled GraphQL introspection and schema registry",
89
89
  "responsibles": 1,
90
- "more": "[guide](https://git.panter.ch/panter/security-guide/-/blob/main/docs/audit/graphql.md)"
90
+ "more": ""
91
91
  },
92
92
  {
93
93
  "description": "The app has set GraphQL complexity query limits",
94
94
  "responsibles": 1,
95
- "more": "[guide](https://git.panter.ch/panter/security-guide/-/blob/main/docs/audit/graphql.md)"
95
+ "more": ""
96
96
  },
97
97
  {
98
98
  "description": "`sitemap.xml` does not leak any routes with sensitive data",
@@ -0,0 +1,23 @@
1
+ import { getGitRemoteHostAndPath } from "../git/gitProjectInformation";
2
+
3
+ /**
4
+ * the base url of the gitlab instance this project lives on.
5
+ *
6
+ * Never hardcode an instance: catladder is used outside panter, and the
7
+ * host was baked in as https://git.panter.ch in several places, which
8
+ * silently broke every consumer on another gitlab.
9
+ *
10
+ * - in a gitlab CI job, `CI_SERVER_URL` is the authoritative value
11
+ * (predefined, already includes the scheme)
12
+ * - locally, derive it from the git remote
13
+ *
14
+ * @param remoteName the remote to derive from outside CI (default origin)
15
+ */
16
+ export const getGitlabHostUrl = async (remoteName = "origin") => {
17
+ const fromCi = process.env.CI_SERVER_URL;
18
+ if (fromCi) {
19
+ return fromCi.replace(/\/+$/, "");
20
+ }
21
+ const { gitRemoteHost } = await getGitRemoteHostAndPath(remoteName);
22
+ return `https://${gitRemoteHost}`;
23
+ };