@kolatts/pncli 1.17.0 → 1.19.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.
package/README.md CHANGED
@@ -68,9 +68,11 @@ pncli uses a three-layer config system (highest priority wins):
68
68
  | `PNCLI_UDEPLOY_PAT` | IBM UrbanCode Deploy personal access token |
69
69
  | `PNCLI_UDEPLOY_USERNAME` | IBM UrbanCode Deploy username (alternative to PAT) |
70
70
  | `PNCLI_UDEPLOY_PASSWORD` | IBM UrbanCode Deploy password (used with `PNCLI_UDEPLOY_USERNAME`) |
71
- | `PNCLI_CHECKMARX_BASE_URL` | Checkmarx CxSAST base URL |
72
- | `PNCLI_CHECKMARX_USERNAME` | Checkmarx username |
73
- | `PNCLI_CHECKMARX_PASSWORD` | Checkmarx password |
71
+ | `PNCLI_CHECKMARX_BASE_URL` | Checkmarx One API base URL |
72
+ | `PNCLI_CHECKMARX_TENANT_NAME` | Checkmarx One tenant name |
73
+ | `PNCLI_CHECKMARX_API_KEY` | Checkmarx One API key |
74
+ | `PNCLI_CHECKMARX_CLIENT_ID` | Checkmarx One OAuth client ID (API key alternative) |
75
+ | `PNCLI_CHECKMARX_CLIENT_SECRET` | Checkmarx One OAuth client secret (API key alternative) |
74
76
  | `PNCLI_CONFIG_PATH` | Override global config file path |
75
77
 
76
78
  ## For AI Agents
@@ -143,7 +143,8 @@ pncli jira get-issue
143
143
  pncli jira create-issue
144
144
  --project <key> Project key
145
145
  --type <type> Issue type (Bug, Story, Task, ...)
146
- --summary <text> Issue summary
146
+ --summary <text> Issue summary (required, unless supplied via
147
+ --input-file)
147
148
  --description <text> Issue description
148
149
  --priority <name> Priority name
149
150
  --assignee <accountId> Assignee account ID
@@ -154,6 +155,9 @@ pncli jira create-issue
154
155
  from file (repeatable) (default: [])
155
156
  --fields-file <path> Path to a JSON file mapping field names/IDs to their
156
157
  Jira API values
158
+ --input-file <path> JSON file describing the whole issue ({ project,
159
+ issueType, fields: {...} }); '-' = stdin. CLI flags
160
+ override matching keys. See: pncli jira schema
157
161
 
158
162
  pncli jira update-issue
159
163
  --key <issue-key> Issue key
@@ -166,6 +170,13 @@ pncli jira update-issue
166
170
  from file (repeatable) (default: [])
167
171
  --fields-file <path> Path to a JSON file mapping field names/IDs to their
168
172
  Jira API values
173
+ --input-file <path> JSON file describing fields to update ({ fields: {...}
174
+ }); '-' = stdin. CLI flags override matching keys.
175
+ See: pncli jira schema
176
+
177
+ pncli jira schema
178
+ --example-only Print only the runnable example JSON (no envelope) — pipeable
179
+ straight into --input-file
169
180
 
170
181
  pncli jira transition-issue
171
182
  --key <issue-key> Issue key
@@ -453,7 +464,12 @@ pncli confluence search
453
464
  pncli confluence create-page
454
465
  --space <key> Space key
455
466
  --title <title> Page title
456
- --body <html> Page body (storage format HTML)
467
+ --body <html> Page body (storage format HTML or Markdown when
468
+ --markdown is set)
469
+ --body-file <path> Path to a file containing the page body ('-' =
470
+ stdin)
471
+ --markdown Convert body from Markdown to storage format via
472
+ Confluence API
457
473
  --parent-id <id> Parent page ID (to nest under a page)
458
474
  --representation <format> Body format: storage (default) or wiki (default:
459
475
  "storage")
@@ -461,7 +477,12 @@ pncli confluence create-page
461
477
  pncli confluence update-page
462
478
  --id <page-id> Page ID
463
479
  --title <title> New page title
464
- --body <html> New page body (storage format HTML)
480
+ --body <html> New page body (storage format HTML or Markdown when
481
+ --markdown is set)
482
+ --body-file <path> Path to a file containing the new page body ('-' =
483
+ stdin)
484
+ --markdown Convert body from Markdown to storage format via
485
+ Confluence API
465
486
  --status <status> Page status: current (default) or draft (default:
466
487
  "current")
467
488
  --representation <format> Body format: storage (default) or wiki (default:
@@ -705,18 +726,26 @@ pncli ado work get
705
726
  --id <n> Work item ID
706
727
 
707
728
  pncli ado work create
708
- --type <type> Work item type (e.g. Bug, Task, User Story)
709
- --title <title> Work item title
729
+ --type <type> Work item type (e.g. Bug, Task, User Story) (required,
730
+ unless supplied via --input-file)
731
+ --title <title> Work item title (required, unless supplied via
732
+ --input-file)
710
733
  --description <text> Description
711
734
  --assignee <user> Assigned to (display name or email)
712
735
  --priority <n> Priority (1-4)
713
736
  --parent <id> Parent work item ID — creates a parent link after
714
737
  creation
715
738
  --field <name=value> Additional field (repeatable) (default: [])
739
+ --input-file <path> JSON file describing the work item ({ type, fields:
740
+ {...} }); '-' = stdin. CLI flags override matching keys.
741
+ See: pncli ado work schema
716
742
 
717
743
  pncli ado work update
718
744
  --id <n> Work item ID
719
745
  --field <name=value> Field to update (repeatable) (default: [])
746
+ --input-file <path> JSON file describing fields to update ({ fields: {...}
747
+ }); '-' = stdin. CLI flags override matching keys. See:
748
+ pncli ado work schema
720
749
 
721
750
  pncli ado work transition
722
751
  --id <n> Work item ID
@@ -763,6 +792,12 @@ pncli ado work download-attachment
763
792
  --attachment-id <guid> Attachment ID from work list-attachments output
764
793
  --dir <path> Output directory (default: .pncli relative to cwd)
765
794
 
795
+ pncli ado work list-areas
796
+ --depth <n> Depth of the area tree to retrieve (default: "10")
797
+
798
+ pncli ado work list-iterations
799
+ --depth <n> Depth of the iteration tree to retrieve (default: "10")
800
+
766
801
  pncli ado work types
767
802
  --discover Fetch from server (always true for this command)
768
803
  --save Save discovered types to ~/.pncli/config.json
@@ -776,6 +811,10 @@ pncli ado work fields
776
811
  --discover Fetch from server (always true for this command)
777
812
  --save Save discovered fields and aliases to ~/.pncli/config.json
778
813
 
814
+ pncli ado work schema
815
+ --example-only Print only the runnable example JSON (no envelope) — pipeable
816
+ straight into --input-file
817
+
779
818
  pncli ado repo list
780
819
 
781
820
  pncli ado repo get
@@ -34,8 +34,10 @@ var ENV_KEYS = {
34
34
  UDEPLOY_USERNAME: "PNCLI_UDEPLOY_USERNAME",
35
35
  UDEPLOY_PASSWORD: "PNCLI_UDEPLOY_PASSWORD",
36
36
  CHECKMARX_BASE_URL: "PNCLI_CHECKMARX_BASE_URL",
37
- CHECKMARX_USERNAME: "PNCLI_CHECKMARX_USERNAME",
38
- CHECKMARX_PASSWORD: "PNCLI_CHECKMARX_PASSWORD",
37
+ CHECKMARX_TENANT_NAME: "PNCLI_CHECKMARX_TENANT_NAME",
38
+ CHECKMARX_API_KEY: "PNCLI_CHECKMARX_API_KEY",
39
+ CHECKMARX_CLIENT_ID: "PNCLI_CHECKMARX_CLIENT_ID",
40
+ CHECKMARX_CLIENT_SECRET: "PNCLI_CHECKMARX_CLIENT_SECRET",
39
41
  SERVICENOW_BASE_URL: "PNCLI_SERVICENOW_BASE_URL",
40
42
  SERVICENOW_USERNAME: "PNCLI_SERVICENOW_USERNAME",
41
43
  SERVICENOW_PASSWORD: "PNCLI_SERVICENOW_PASSWORD",
@@ -50,6 +52,10 @@ var ENV_KEYS = {
50
52
  SONATYPEIQ_PASSCODE: "PNCLI_SONATYPEIQ_PASSCODE",
51
53
  OPENSHIFT_BASE_URL: "PNCLI_OPENSHIFT_BASE_URL",
52
54
  OPENSHIFT_TOKEN: "PNCLI_OPENSHIFT_TOKEN",
55
+ DYNATRACE_BASE_URL: "PNCLI_DYNATRACE_BASE_URL",
56
+ DYNATRACE_API_TOKEN: "PNCLI_DYNATRACE_API_TOKEN",
57
+ DYNATRACE_PLATFORM_URL: "PNCLI_DYNATRACE_PLATFORM_URL",
58
+ DYNATRACE_PLATFORM_TOKEN: "PNCLI_DYNATRACE_PLATFORM_TOKEN",
53
59
  CONFIG_PATH: "PNCLI_CONFIG_PATH"
54
60
  };
55
61
  function getGlobalConfigPath(overridePath) {
@@ -167,8 +173,10 @@ function loadConfig(opts = {}) {
167
173
  },
168
174
  checkmarx: {
169
175
  baseUrl: process.env[ENV_KEYS.CHECKMARX_BASE_URL] ?? globalConfig.checkmarx?.baseUrl,
170
- username: process.env[ENV_KEYS.CHECKMARX_USERNAME] ?? globalConfig.checkmarx?.username,
171
- password: process.env[ENV_KEYS.CHECKMARX_PASSWORD] ?? globalConfig.checkmarx?.password
176
+ tenantName: process.env[ENV_KEYS.CHECKMARX_TENANT_NAME] ?? globalConfig.checkmarx?.tenantName,
177
+ apiKey: process.env[ENV_KEYS.CHECKMARX_API_KEY] ?? globalConfig.checkmarx?.apiKey,
178
+ clientId: process.env[ENV_KEYS.CHECKMARX_CLIENT_ID] ?? globalConfig.checkmarx?.clientId,
179
+ clientSecret: process.env[ENV_KEYS.CHECKMARX_CLIENT_SECRET] ?? globalConfig.checkmarx?.clientSecret
172
180
  },
173
181
  servicenow: {
174
182
  baseUrl: process.env[ENV_KEYS.SERVICENOW_BASE_URL] ?? globalConfig.servicenow?.baseUrl,
@@ -192,6 +200,12 @@ function loadConfig(opts = {}) {
192
200
  baseUrl: process.env[ENV_KEYS.OPENSHIFT_BASE_URL] ?? globalConfig.openshift?.baseUrl,
193
201
  token: process.env[ENV_KEYS.OPENSHIFT_TOKEN] ?? globalConfig.openshift?.token
194
202
  },
203
+ dynatrace: {
204
+ baseUrl: process.env[ENV_KEYS.DYNATRACE_BASE_URL] ?? globalConfig.dynatrace?.baseUrl,
205
+ apiToken: process.env[ENV_KEYS.DYNATRACE_API_TOKEN] ?? globalConfig.dynatrace?.apiToken,
206
+ platformUrl: process.env[ENV_KEYS.DYNATRACE_PLATFORM_URL] ?? globalConfig.dynatrace?.platformUrl,
207
+ platformToken: process.env[ENV_KEYS.DYNATRACE_PLATFORM_TOKEN] ?? globalConfig.dynatrace?.platformToken
208
+ },
195
209
  defaults: mergedDefaults
196
210
  };
197
211
  }
@@ -208,6 +222,16 @@ function writeRepoConfig(config) {
208
222
  const targetDir = repoRoot ?? process.cwd();
209
223
  fs.writeFileSync(path.join(targetDir, ".pncli.json"), JSON.stringify(config, null, 2) + "\n", "utf8");
210
224
  }
225
+ function parseConfigValue(value) {
226
+ try {
227
+ const parsed = JSON.parse(value);
228
+ if (typeof parsed === "object" && parsed !== null) {
229
+ return parsed;
230
+ }
231
+ } catch {
232
+ }
233
+ return value;
234
+ }
211
235
  function setConfigValue(key, value, configPath) {
212
236
  const filePath = getGlobalConfigPath(configPath);
213
237
  const existing = loadJsonFile(filePath) ?? {};
@@ -220,7 +244,7 @@ function setConfigValue(key, value, configPath) {
220
244
  }
221
245
  current = current[part];
222
246
  }
223
- current[parts[parts.length - 1]] = value;
247
+ current[parts[parts.length - 1]] = parseConfigValue(value);
224
248
  writeGlobalConfig(existing, configPath);
225
249
  }
226
250
  function setRepoConfigValue(key, value) {
@@ -237,7 +261,7 @@ function setRepoConfigValue(key, value) {
237
261
  }
238
262
  current = current[part];
239
263
  }
240
- current[parts[parts.length - 1]] = value;
264
+ current[parts[parts.length - 1]] = parseConfigValue(value);
241
265
  writeRepoConfig(existing);
242
266
  }
243
267
  function maskConfig(config) {
@@ -287,7 +311,8 @@ function maskConfig(config) {
287
311
  },
288
312
  checkmarx: {
289
313
  ...config.checkmarx,
290
- password: config.checkmarx.password ? "***" : void 0
314
+ apiKey: config.checkmarx.apiKey ? "***" : void 0,
315
+ clientSecret: config.checkmarx.clientSecret ? "***" : void 0
291
316
  },
292
317
  servicenow: {
293
318
  ...config.servicenow,
@@ -306,6 +331,11 @@ function maskConfig(config) {
306
331
  openshift: {
307
332
  ...config.openshift,
308
333
  token: config.openshift.token ? "***" : void 0
334
+ },
335
+ dynatrace: {
336
+ ...config.dynatrace,
337
+ apiToken: config.dynatrace.apiToken ? "***" : void 0,
338
+ platformToken: config.dynatrace.platformToken ? "***" : void 0
309
339
  }
310
340
  };
311
341
  }
@@ -320,4 +350,4 @@ export {
320
350
  setRepoConfigValue,
321
351
  maskConfig
322
352
  };
323
- //# sourceMappingURL=chunk-FFVQ4PA7.js.map
353
+ //# sourceMappingURL=chunk-FXY262BR.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/config.ts"],"sourcesContent":["import fs from 'fs';\nimport os from 'os';\nimport path from 'path';\nimport { execSync } from 'child_process';\nimport type { GlobalConfig, RepoConfig, ResolvedConfig, JiraDefaults, BitbucketDefaults, GitHubDefaults, SonarDefaults, SdeDefaults, AdoDefaults, UdeployDefaults, JenkinsDefaults } from '../types/config.js';\nimport type { CustomFieldDefinition } from '../types/jira.js';\n\nconst ENV_KEYS = {\n EMAIL: 'PNCLI_EMAIL',\n USERID: 'PNCLI_USERID',\n JIRA_BASE_URL: 'PNCLI_JIRA_BASE_URL',\n JIRA_API_TOKEN: 'PNCLI_JIRA_API_TOKEN',\n BITBUCKET_BASE_URL: 'PNCLI_BITBUCKET_BASE_URL',\n BITBUCKET_PAT: 'PNCLI_BITBUCKET_PAT',\n GITHUB_BASE_URL: 'PNCLI_GITHUB_BASE_URL',\n GITHUB_TOKEN: 'PNCLI_GITHUB_TOKEN',\n CONFLUENCE_BASE_URL: 'PNCLI_CONFLUENCE_BASE_URL',\n CONFLUENCE_API_TOKEN: 'PNCLI_CONFLUENCE_API_TOKEN',\n ARTIFACTORY_BASE_URL: 'PNCLI_ARTIFACTORY_BASE_URL',\n ARTIFACTORY_TOKEN: 'PNCLI_ARTIFACTORY_TOKEN',\n ARTIFACTORY_REPO_NPM: 'PNCLI_ARTIFACTORY_REPO_NPM',\n ARTIFACTORY_REPO_NUGET: 'PNCLI_ARTIFACTORY_REPO_NUGET',\n ARTIFACTORY_REPO_MAVEN: 'PNCLI_ARTIFACTORY_REPO_MAVEN',\n SONAR_BASE_URL: 'PNCLI_SONAR_BASE_URL',\n SONAR_TOKEN: 'PNCLI_SONAR_TOKEN',\n SDE_CONNECTION: 'PNCLI_SDE_CONNECTION',\n ADO_BASE_URL: 'PNCLI_ADO_BASE_URL',\n ADO_PAT: 'PNCLI_ADO_PAT',\n JENKINS_BASE_URL: 'PNCLI_JENKINS_BASE_URL',\n JENKINS_USERNAME: 'PNCLI_JENKINS_USERNAME',\n JENKINS_API_TOKEN: 'PNCLI_JENKINS_API_TOKEN',\n UDEPLOY_BASE_URL: 'PNCLI_UDEPLOY_BASE_URL',\n UDEPLOY_PAT: 'PNCLI_UDEPLOY_PAT',\n UDEPLOY_USERNAME: 'PNCLI_UDEPLOY_USERNAME',\n UDEPLOY_PASSWORD: 'PNCLI_UDEPLOY_PASSWORD',\n CHECKMARX_BASE_URL: 'PNCLI_CHECKMARX_BASE_URL',\n CHECKMARX_TENANT_NAME: 'PNCLI_CHECKMARX_TENANT_NAME',\n CHECKMARX_API_KEY: 'PNCLI_CHECKMARX_API_KEY',\n CHECKMARX_CLIENT_ID: 'PNCLI_CHECKMARX_CLIENT_ID',\n CHECKMARX_CLIENT_SECRET: 'PNCLI_CHECKMARX_CLIENT_SECRET',\n SERVICENOW_BASE_URL: 'PNCLI_SERVICENOW_BASE_URL',\n SERVICENOW_USERNAME: 'PNCLI_SERVICENOW_USERNAME',\n SERVICENOW_PASSWORD: 'PNCLI_SERVICENOW_PASSWORD',\n SERVICENOW_API_TOKEN: 'PNCLI_SERVICENOW_API_TOKEN',\n CONTRAST_BASE_URL: 'PNCLI_CONTRAST_BASE_URL',\n CONTRAST_ORG_UUID: 'PNCLI_CONTRAST_ORG_UUID',\n CONTRAST_API_KEY: 'PNCLI_CONTRAST_API_KEY',\n CONTRAST_SERVICE_KEY: 'PNCLI_CONTRAST_SERVICE_KEY',\n CONTRAST_USERNAME: 'PNCLI_CONTRAST_USERNAME',\n SONATYPEIQ_BASE_URL: 'PNCLI_SONATYPEIQ_BASE_URL',\n SONATYPEIQ_USER_CODE: 'PNCLI_SONATYPEIQ_USER_CODE',\n SONATYPEIQ_PASSCODE: 'PNCLI_SONATYPEIQ_PASSCODE',\n OPENSHIFT_BASE_URL: 'PNCLI_OPENSHIFT_BASE_URL',\n OPENSHIFT_TOKEN: 'PNCLI_OPENSHIFT_TOKEN',\n DYNATRACE_BASE_URL: 'PNCLI_DYNATRACE_BASE_URL',\n DYNATRACE_API_TOKEN: 'PNCLI_DYNATRACE_API_TOKEN',\n DYNATRACE_PLATFORM_URL: 'PNCLI_DYNATRACE_PLATFORM_URL',\n DYNATRACE_PLATFORM_TOKEN: 'PNCLI_DYNATRACE_PLATFORM_TOKEN',\n CONFIG_PATH: 'PNCLI_CONFIG_PATH'\n} as const;\n\nfunction getGlobalConfigPath(overridePath?: string): string {\n if (overridePath) return overridePath;\n const envPath = process.env[ENV_KEYS.CONFIG_PATH];\n if (envPath) return envPath;\n return path.join(os.homedir(), '.pncli', 'config.json');\n}\n\nfunction loadJsonFile<T>(filePath: string): T | null {\n try {\n const content = fs.readFileSync(filePath, 'utf8');\n return JSON.parse(content) as T;\n } catch {\n return null;\n }\n}\n\nfunction getRepoRoot(): string | null {\n try {\n return execSync('git rev-parse --show-toplevel', { encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'] }).trim();\n } catch {\n return null;\n }\n}\n\nfunction parseSdeConnection(connection: string): { token: string; baseUrl: string } | null {\n const idx = connection.indexOf('@');\n if (idx <= 0) return null;\n const token = connection.slice(0, idx);\n const host = connection.slice(idx + 1);\n const baseUrl = /^https?:\\/\\//i.test(host) ? host : `https://${host}`;\n return { token, baseUrl };\n}\n\nfunction mergeCustomFields(\n global: CustomFieldDefinition[] | undefined,\n repo: CustomFieldDefinition[] | undefined\n): CustomFieldDefinition[] {\n const map = new Map<string, CustomFieldDefinition>();\n for (const f of global ?? []) map.set(f.id, f);\n for (const f of repo ?? []) map.set(f.id, f); // repo wins\n return Array.from(map.values());\n}\n\nfunction mergeDefaults(\n global: GlobalConfig['defaults'],\n repo: RepoConfig['defaults']\n): { jira: JiraDefaults; bitbucket: BitbucketDefaults; github: GitHubDefaults; sonar: SonarDefaults; sde: SdeDefaults; ado: AdoDefaults; udeploy: UdeployDefaults; jenkins: JenkinsDefaults } {\n return {\n jira: { ...global?.jira, ...repo?.jira },\n bitbucket: { ...global?.bitbucket, ...repo?.bitbucket },\n github: { ...global?.github, ...repo?.github },\n sonar: { ...global?.sonar, ...repo?.sonar },\n sde: { ...global?.sde, ...repo?.sde },\n ado: { ...global?.ado, ...repo?.ado },\n udeploy: { ...global?.udeploy, ...repo?.udeploy },\n jenkins: { ...global?.jenkins, ...repo?.jenkins }\n };\n}\n\nexport interface LoadConfigOptions {\n configPath?: string;\n}\n\nexport function loadConfig(opts: LoadConfigOptions = {}): ResolvedConfig {\n const globalConfigPath = getGlobalConfigPath(opts.configPath);\n const globalConfig = loadJsonFile<GlobalConfig>(globalConfigPath) ?? {};\n\n const repoRoot = getRepoRoot();\n let repoConfig: RepoConfig = {};\n if (repoRoot) {\n repoConfig = loadJsonFile<RepoConfig>(path.join(repoRoot, '.pncli.json')) ?? {};\n }\n\n const mergedDefaults = mergeDefaults(globalConfig.defaults, repoConfig.defaults);\n\n return {\n user: {\n email: process.env[ENV_KEYS.EMAIL] ?? globalConfig.user?.email,\n userId: process.env[ENV_KEYS.USERID] ?? globalConfig.user?.userId\n },\n jira: {\n baseUrl: process.env[ENV_KEYS.JIRA_BASE_URL] ?? globalConfig.jira?.baseUrl,\n apiToken: process.env[ENV_KEYS.JIRA_API_TOKEN] ?? globalConfig.jira?.apiToken,\n customFields: mergeCustomFields(globalConfig.jira?.customFields, repoConfig.jira?.customFields)\n },\n bitbucket: {\n baseUrl: process.env[ENV_KEYS.BITBUCKET_BASE_URL] ?? globalConfig.bitbucket?.baseUrl,\n pat: process.env[ENV_KEYS.BITBUCKET_PAT] ?? globalConfig.bitbucket?.pat\n },\n github: {\n baseUrl: process.env[ENV_KEYS.GITHUB_BASE_URL] ?? globalConfig.github?.baseUrl,\n token: process.env[ENV_KEYS.GITHUB_TOKEN] ?? globalConfig.github?.token\n },\n confluence: {\n baseUrl: process.env[ENV_KEYS.CONFLUENCE_BASE_URL] ?? globalConfig.confluence?.baseUrl,\n apiToken: process.env[ENV_KEYS.CONFLUENCE_API_TOKEN] ?? globalConfig.confluence?.apiToken\n ?? process.env[ENV_KEYS.JIRA_API_TOKEN] ?? globalConfig.jira?.apiToken,\n apiTokenExplicit: !!(\n process.env[ENV_KEYS.CONFLUENCE_API_TOKEN] ?? globalConfig.confluence?.apiToken\n )\n },\n artifactory: {\n baseUrl: process.env[ENV_KEYS.ARTIFACTORY_BASE_URL] ?? globalConfig.artifactory?.baseUrl,\n token: process.env[ENV_KEYS.ARTIFACTORY_TOKEN] ?? globalConfig.artifactory?.token,\n npmRepo: process.env[ENV_KEYS.ARTIFACTORY_REPO_NPM] ?? globalConfig.artifactory?.npmRepo,\n nugetRepo: process.env[ENV_KEYS.ARTIFACTORY_REPO_NUGET] ?? globalConfig.artifactory?.nugetRepo,\n mavenRepo: process.env[ENV_KEYS.ARTIFACTORY_REPO_MAVEN] ?? globalConfig.artifactory?.mavenRepo\n },\n sonar: {\n baseUrl: process.env[ENV_KEYS.SONAR_BASE_URL] ?? globalConfig.sonar?.baseUrl,\n token: process.env[ENV_KEYS.SONAR_TOKEN] ?? globalConfig.sonar?.token\n },\n sde: (() => {\n const raw = process.env[ENV_KEYS.SDE_CONNECTION] ?? globalConfig.sde?.connection;\n const parsed = raw ? parseSdeConnection(raw) : null;\n return { baseUrl: parsed?.baseUrl, token: parsed?.token };\n })(),\n ado: {\n baseUrl: process.env[ENV_KEYS.ADO_BASE_URL] ?? globalConfig.ado?.baseUrl,\n pat: process.env[ENV_KEYS.ADO_PAT] ?? globalConfig.ado?.pat,\n fieldAliases: globalConfig.ado?.fieldAliases ?? {},\n discoveredFields: globalConfig.ado?.discoveredFields ?? [],\n discoveredTypes: globalConfig.ado?.discoveredTypes ?? []\n },\n jenkins: {\n baseUrl: repoConfig.defaults?.jenkins?.baseUrl ?? process.env[ENV_KEYS.JENKINS_BASE_URL] ?? globalConfig.jenkins?.baseUrl,\n username: process.env[ENV_KEYS.JENKINS_USERNAME] ?? globalConfig.jenkins?.username,\n apiToken: process.env[ENV_KEYS.JENKINS_API_TOKEN] ?? globalConfig.jenkins?.apiToken\n },\n udeploy: {\n baseUrl: process.env[ENV_KEYS.UDEPLOY_BASE_URL] ?? globalConfig.udeploy?.baseUrl,\n pat: process.env[ENV_KEYS.UDEPLOY_PAT] ?? globalConfig.udeploy?.pat,\n username: process.env[ENV_KEYS.UDEPLOY_USERNAME] ?? globalConfig.udeploy?.username,\n password: process.env[ENV_KEYS.UDEPLOY_PASSWORD] ?? globalConfig.udeploy?.password,\n },\n checkmarx: {\n baseUrl: process.env[ENV_KEYS.CHECKMARX_BASE_URL] ?? globalConfig.checkmarx?.baseUrl,\n tenantName: process.env[ENV_KEYS.CHECKMARX_TENANT_NAME] ?? globalConfig.checkmarx?.tenantName,\n apiKey: process.env[ENV_KEYS.CHECKMARX_API_KEY] ?? globalConfig.checkmarx?.apiKey,\n clientId: process.env[ENV_KEYS.CHECKMARX_CLIENT_ID] ?? globalConfig.checkmarx?.clientId,\n clientSecret: process.env[ENV_KEYS.CHECKMARX_CLIENT_SECRET] ?? globalConfig.checkmarx?.clientSecret,\n },\n servicenow: {\n baseUrl: process.env[ENV_KEYS.SERVICENOW_BASE_URL] ?? globalConfig.servicenow?.baseUrl,\n username: process.env[ENV_KEYS.SERVICENOW_USERNAME] ?? globalConfig.servicenow?.username,\n password: process.env[ENV_KEYS.SERVICENOW_PASSWORD] ?? globalConfig.servicenow?.password,\n apiToken: process.env[ENV_KEYS.SERVICENOW_API_TOKEN] ?? globalConfig.servicenow?.apiToken,\n },\n contrast: {\n baseUrl: process.env[ENV_KEYS.CONTRAST_BASE_URL] ?? globalConfig.contrast?.baseUrl,\n orgUuid: process.env[ENV_KEYS.CONTRAST_ORG_UUID] ?? globalConfig.contrast?.orgUuid,\n apiKey: process.env[ENV_KEYS.CONTRAST_API_KEY] ?? globalConfig.contrast?.apiKey,\n serviceKey: process.env[ENV_KEYS.CONTRAST_SERVICE_KEY] ?? globalConfig.contrast?.serviceKey,\n username: process.env[ENV_KEYS.CONTRAST_USERNAME] ?? globalConfig.contrast?.username,\n },\n sonatypeiq: {\n baseUrl: process.env[ENV_KEYS.SONATYPEIQ_BASE_URL] ?? globalConfig.sonatypeiq?.baseUrl,\n userCode: process.env[ENV_KEYS.SONATYPEIQ_USER_CODE] ?? globalConfig.sonatypeiq?.userCode,\n passcode: process.env[ENV_KEYS.SONATYPEIQ_PASSCODE] ?? globalConfig.sonatypeiq?.passcode,\n },\n openshift: {\n baseUrl: process.env[ENV_KEYS.OPENSHIFT_BASE_URL] ?? globalConfig.openshift?.baseUrl,\n token: process.env[ENV_KEYS.OPENSHIFT_TOKEN] ?? globalConfig.openshift?.token,\n },\n dynatrace: {\n baseUrl: process.env[ENV_KEYS.DYNATRACE_BASE_URL] ?? globalConfig.dynatrace?.baseUrl,\n apiToken: process.env[ENV_KEYS.DYNATRACE_API_TOKEN] ?? globalConfig.dynatrace?.apiToken,\n platformUrl: process.env[ENV_KEYS.DYNATRACE_PLATFORM_URL] ?? globalConfig.dynatrace?.platformUrl,\n platformToken: process.env[ENV_KEYS.DYNATRACE_PLATFORM_TOKEN] ?? globalConfig.dynatrace?.platformToken,\n },\n defaults: mergedDefaults\n };\n}\n\nexport function writeGlobalConfig(config: GlobalConfig, configPath?: string): void {\n const filePath = getGlobalConfigPath(configPath);\n const dir = path.dirname(filePath);\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true });\n }\n fs.writeFileSync(filePath, JSON.stringify(config, null, 2) + '\\n', 'utf8');\n}\n\nexport function writeRepoConfig(config: RepoConfig): void {\n const repoRoot = getRepoRoot();\n const targetDir = repoRoot ?? process.cwd();\n fs.writeFileSync(path.join(targetDir, '.pncli.json'), JSON.stringify(config, null, 2) + '\\n', 'utf8');\n}\n\nfunction parseConfigValue(value: string): unknown {\n try {\n const parsed = JSON.parse(value);\n if (typeof parsed === 'object' && parsed !== null) {\n return parsed;\n }\n } catch {\n // not valid JSON — fall through to raw string\n }\n return value;\n}\n\nexport function setConfigValue(key: string, value: string, configPath?: string): void {\n const filePath = getGlobalConfigPath(configPath);\n const existing = loadJsonFile<GlobalConfig>(filePath) ?? {};\n\n const parts = key.split('.');\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let current: any = existing;\n for (let i = 0; i < parts.length - 1; i++) {\n const part = parts[i]!;\n if (typeof current[part] !== 'object' || current[part] === null) {\n current[part] = {};\n }\n current = current[part];\n }\n current[parts[parts.length - 1]!] = parseConfigValue(value);\n\n writeGlobalConfig(existing, configPath);\n}\n\nexport function setRepoConfigValue(key: string, value: string): void {\n const repoRoot = getRepoRoot();\n const targetDir = repoRoot ?? process.cwd();\n const filePath = path.join(targetDir, '.pncli.json');\n const existing = loadJsonFile<RepoConfig>(filePath) ?? {};\n\n const parts = key.split('.');\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let current: any = existing;\n for (let i = 0; i < parts.length - 1; i++) {\n const part = parts[i]!;\n if (typeof current[part] !== 'object' || current[part] === null) {\n current[part] = {};\n }\n current = current[part];\n }\n current[parts[parts.length - 1]!] = parseConfigValue(value);\n\n writeRepoConfig(existing);\n}\n\nexport function maskConfig(config: ResolvedConfig): unknown {\n return {\n ...config,\n jira: {\n ...config.jira,\n apiToken: config.jira.apiToken ? '***' : undefined,\n customFields: config.jira.customFields\n },\n bitbucket: {\n ...config.bitbucket,\n pat: config.bitbucket.pat ? '***' : undefined\n },\n github: {\n ...config.github,\n token: config.github.token ? '***' : undefined\n },\n confluence: {\n ...config.confluence,\n apiToken: config.confluence.apiToken ? '***' : undefined\n },\n artifactory: {\n ...config.artifactory,\n token: config.artifactory.token ? '***' : undefined\n },\n sonar: {\n ...config.sonar,\n token: config.sonar.token ? '***' : undefined\n },\n sde: {\n baseUrl: config.sde.baseUrl,\n token: config.sde.token ? '***' : undefined\n },\n ado: {\n ...config.ado,\n pat: config.ado.pat ? '***' : undefined\n },\n jenkins: {\n ...config.jenkins,\n apiToken: config.jenkins.apiToken ? '***' : undefined\n },\n udeploy: {\n ...config.udeploy,\n pat: config.udeploy.pat ? '***' : undefined,\n password: config.udeploy.password ? '***' : undefined\n },\n checkmarx: {\n ...config.checkmarx,\n apiKey: config.checkmarx.apiKey ? '***' : undefined,\n clientSecret: config.checkmarx.clientSecret ? '***' : undefined\n },\n servicenow: {\n ...config.servicenow,\n password: config.servicenow.password ? '***' : undefined,\n apiToken: config.servicenow.apiToken ? '***' : undefined\n },\n contrast: {\n ...config.contrast,\n apiKey: config.contrast.apiKey ? '***' : undefined,\n serviceKey: config.contrast.serviceKey ? '***' : undefined\n },\n sonatypeiq: {\n ...config.sonatypeiq,\n passcode: config.sonatypeiq.passcode ? '***' : undefined\n },\n openshift: {\n ...config.openshift,\n token: config.openshift.token ? '***' : undefined\n },\n dynatrace: {\n ...config.dynatrace,\n apiToken: config.dynatrace.apiToken ? '***' : undefined,\n platformToken: config.dynatrace.platformToken ? '***' : undefined\n }\n };\n}\n\nexport { getGlobalConfigPath, loadJsonFile };\n"],"mappings":"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","names":[]}
@@ -49,13 +49,14 @@ function isDebugEnabled() {
49
49
  function setGlobalUser(user) {
50
50
  globalUser = user;
51
51
  }
52
- function buildMeta(service, action, startTime) {
52
+ function buildMeta(service, action, startTime, overrides) {
53
53
  return {
54
54
  service,
55
55
  action,
56
56
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
57
57
  duration_ms: Date.now() - startTime,
58
- user: globalUser.email ?? globalUser.userId ? globalUser : void 0
58
+ user: globalUser.email ?? globalUser.userId ? globalUser : void 0,
59
+ overrides: overrides && overrides.length > 0 ? overrides : void 0
59
60
  };
60
61
  }
61
62
  function writeToFile(filePath, content) {
@@ -69,11 +70,11 @@ function writeToFile(filePath, content) {
69
70
  process.exitCode = ExitCode.GENERAL_ERROR;
70
71
  }
71
72
  }
72
- function success(data, service, action, startTime) {
73
+ function success(data, service, action, startTime, overrides) {
73
74
  const envelope = {
74
75
  ok: true,
75
76
  data,
76
- meta: buildMeta(service, action, startTime)
77
+ meta: buildMeta(service, action, startTime, overrides)
77
78
  };
78
79
  const out = (globalOptions.pretty ? JSON.stringify(envelope, null, 2) : JSON.stringify(envelope)) + "\n";
79
80
  if (outputFile) {
@@ -162,30 +163,33 @@ async function buildAdoFetcher(config) {
162
163
  }
163
164
 
164
165
  // src/lib/checkmarxFetch.ts
165
- var CX_CLIENT_ID = "resource_owner_client";
166
- var CX_CLIENT_SECRET = "014DF517-39D1-4453-B7B3-9930C563627C";
167
- var CX_SCOPE = "sast_api offline_access";
168
166
  function buildCheckmarxFetcher(config) {
169
- const { baseUrl, username, password } = config.checkmarx;
167
+ const { baseUrl, tenantName, apiKey, clientId, clientSecret } = config.checkmarx;
170
168
  if (!baseUrl) throw new PncliError("Checkmarx baseUrl not configured. Run: pncli config init", 1);
171
- if (!username) throw new PncliError("Checkmarx username not configured. Run: pncli config init", 1);
172
- if (!password) throw new PncliError("Checkmarx password not configured. Run: pncli config init", 1);
173
- const resolvedUsername = username;
174
- const resolvedPassword = password;
175
- const tokenUrl = `${baseUrl.replace(/\/$/, "")}/cxrestapi/auth/identity/connect/token`;
169
+ if (!tenantName) throw new PncliError("Checkmarx tenantName not configured. Run: pncli config init", 1);
170
+ if (!apiKey && (!clientId || !clientSecret)) {
171
+ throw new PncliError(
172
+ "Checkmarx credentials not configured. Set apiKey or clientId and clientSecret. Run: pncli config init",
173
+ 1
174
+ );
175
+ }
176
+ const apiHost = new URL(baseUrl).hostname;
177
+ const iamHost = apiHost.replace(/(^|\.)ast\./, "$1iam.");
178
+ const tokenUrl = `https://${iamHost}/auth/realms/${tenantName}/protocol/openid-connect/token`;
176
179
  let cache = null;
177
180
  async function getToken() {
178
181
  const now = Date.now();
179
182
  if (cache && cache.expiresAt - now > 6e4) {
180
183
  return cache.value;
181
184
  }
182
- const body = new URLSearchParams({
183
- grant_type: "password",
184
- client_id: CX_CLIENT_ID,
185
- client_secret: CX_CLIENT_SECRET,
186
- scope: CX_SCOPE,
187
- username: resolvedUsername,
188
- password: resolvedPassword
185
+ const body = apiKey ? new URLSearchParams({
186
+ grant_type: "refresh_token",
187
+ client_id: getApiKeyClientId(apiKey),
188
+ refresh_token: apiKey
189
+ }) : new URLSearchParams({
190
+ grant_type: "client_credentials",
191
+ client_id: clientId,
192
+ client_secret: clientSecret
189
193
  });
190
194
  const response = await fetch(tokenUrl, {
191
195
  method: "POST",
@@ -220,6 +224,17 @@ function buildCheckmarxFetcher(config) {
220
224
  });
221
225
  };
222
226
  }
227
+ function getApiKeyClientId(apiKey) {
228
+ try {
229
+ const payload = apiKey.split(".")[1];
230
+ if (!payload) return "ast-app";
231
+ const normalized = payload.replace(/-/g, "+").replace(/_/g, "/");
232
+ const claims = JSON.parse(Buffer.from(normalized, "base64").toString("utf8"));
233
+ return typeof claims.azp === "string" && claims.azp ? claims.azp : "ast-app";
234
+ } catch {
235
+ return "ast-app";
236
+ }
237
+ }
223
238
 
224
239
  // src/lib/http.ts
225
240
  var SENSITIVE_HEADERS = /* @__PURE__ */ new Set(["authorization", "api-key"]);
@@ -238,7 +253,9 @@ function redactHeaders(headers) {
238
253
  );
239
254
  }
240
255
  function buildUrl(base, path, params) {
241
- const url = new URL(path, base.endsWith("/") ? base : base + "/");
256
+ const normalizedBase = base.endsWith("/") ? base : base + "/";
257
+ const normalizedPath = path.startsWith("/") ? path.slice(1) : path;
258
+ const url = new URL(normalizedPath, normalizedBase);
242
259
  if (params) {
243
260
  for (const [key, val] of Object.entries(params)) {
244
261
  if (val !== void 0) {
@@ -555,11 +572,14 @@ Headers: ${JSON.stringify(safeHeaders, null, 2)}
555
572
  }
556
573
  return request(url, init, opts.timeoutMs ?? 3e4);
557
574
  }
558
- confluenceHeaders() {
575
+ confluenceToken() {
559
576
  const { apiToken } = this.config.confluence;
560
577
  if (!apiToken) throw new PncliError("Confluence credentials not configured. Run: pncli config init");
578
+ return apiToken;
579
+ }
580
+ confluenceHeaders() {
561
581
  return {
562
- "Authorization": `Bearer ${apiToken}`,
582
+ "Authorization": `Bearer ${this.confluenceToken()}`,
563
583
  "Content-Type": "application/json",
564
584
  "Accept": "application/json",
565
585
  "Connection": "close"
@@ -947,6 +967,28 @@ Headers: ${JSON.stringify(safeHeaders, null, 2)}
947
967
  }
948
968
  return results;
949
969
  }
970
+ async confluenceUpload(path, formData, opts = {}) {
971
+ const baseUrl = this.config.confluence.baseUrl;
972
+ if (!baseUrl) throw new PncliError("Confluence baseUrl not configured. Run: pncli config init");
973
+ const url = buildUrl(baseUrl, path);
974
+ const headers = {
975
+ "Authorization": `Bearer ${this.confluenceToken()}`,
976
+ "X-Atlassian-Token": "no-check",
977
+ "Accept": "application/json",
978
+ "Connection": "close"
979
+ };
980
+ if (this.dryRun) {
981
+ const safeHeaders = { ...headers, Authorization: "[REDACTED]" };
982
+ const msg = `DRY RUN: POST ${url}
983
+ Headers: ${JSON.stringify(safeHeaders, null, 2)}
984
+ Body: <multipart/form-data>
985
+ `;
986
+ fs2.writeSync(process.stderr.fd, msg);
987
+ process.exitCode = ExitCode.SUCCESS;
988
+ throw new PncliError("dry-run", 0);
989
+ }
990
+ return request(url, { method: "POST", headers, body: formData }, opts.timeoutMs ?? 6e4);
991
+ }
950
992
  async confluencePaginate(fetchPage, maxTotal) {
951
993
  const results = [];
952
994
  let start = 0;
@@ -1125,6 +1167,52 @@ Headers: ${JSON.stringify(safeHeaders, null, 2)}
1125
1167
  const msg = `DRY RUN: ${init.method} ${url}
1126
1168
  Headers: ${JSON.stringify(safeHeaders, null, 2)}
1127
1169
  ` + (opts.body ? `Body: ${JSON.stringify(opts.body, null, 2)}
1170
+ ` : "");
1171
+ fs2.writeSync(process.stderr.fd, msg);
1172
+ process.exitCode = ExitCode.SUCCESS;
1173
+ throw new PncliError("dry-run", 0);
1174
+ }
1175
+ return request(url, init, opts.timeoutMs ?? 3e4);
1176
+ }
1177
+ dynatraceHeaders(platform = false) {
1178
+ const token = platform ? this.config.dynatrace.platformToken : this.config.dynatrace.apiToken;
1179
+ if (!token) {
1180
+ throw new PncliError(
1181
+ `${platform ? "Dynatrace platform" : "Dynatrace"} credentials not configured. Run: pncli config init`
1182
+ );
1183
+ }
1184
+ return {
1185
+ "Authorization": `${platform ? "Bearer" : "Api-Token"} ${token}`,
1186
+ "Content-Type": "application/json",
1187
+ "Accept": "application/json",
1188
+ "Connection": "close"
1189
+ };
1190
+ }
1191
+ async dynatrace(path, opts = {}) {
1192
+ return this.dynatraceRequest(false, path, opts);
1193
+ }
1194
+ async dynatracePlatform(path, opts = {}) {
1195
+ return this.dynatraceRequest(true, path, opts);
1196
+ }
1197
+ async dynatraceRequest(platform, path, opts) {
1198
+ const baseUrl = platform ? this.config.dynatrace.platformUrl : this.config.dynatrace.baseUrl;
1199
+ if (!baseUrl) {
1200
+ throw new PncliError(
1201
+ `${platform ? "Dynatrace platformUrl" : "Dynatrace baseUrl"} not configured. Run: pncli config init`
1202
+ );
1203
+ }
1204
+ const url = buildUrl(baseUrl, path, opts.params);
1205
+ const headers = this.dynatraceHeaders(platform);
1206
+ const init = {
1207
+ method: opts.method ?? "GET",
1208
+ headers,
1209
+ body: opts.body !== void 0 ? JSON.stringify(opts.body) : void 0
1210
+ };
1211
+ if (this.dryRun) {
1212
+ const safeHeaders = { ...headers, Authorization: "[REDACTED]" };
1213
+ const msg = `DRY RUN: ${init.method} ${url}
1214
+ Headers: ${JSON.stringify(safeHeaders, null, 2)}
1215
+ ` + (opts.body ? `Body: ${JSON.stringify(opts.body, null, 2)}
1128
1216
  ` : "");
1129
1217
  fs2.writeSync(process.stderr.fd, msg);
1130
1218
  process.exitCode = ExitCode.SUCCESS;
@@ -1201,4 +1289,4 @@ export {
1201
1289
  HttpClient,
1202
1290
  createHttpClient
1203
1291
  };
1204
- //# sourceMappingURL=chunk-XPPEXJBP.js.map
1292
+ //# sourceMappingURL=chunk-WM5NYVEO.js.map