Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
300 changes: 150 additions & 150 deletions CHANGELOG.md

Large diffs are not rendered by default.

22 changes: 22 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,28 @@ pncli integrations must be self-contained. Users cannot be required to have any

Unit tests must exercise internal logic — auth header construction, URL building, response parsing, config resolution, token-cache expiry — by stubbing `fetch` (see `src/lib/http.test.ts` for the pattern). Tests must never depend on a live external service being reachable; a developer running `npm test` offline or on a locked-down CI runner must get the same pass/fail result as one with full network access. Connectivity against real services is what `pncli config test` is for, not the unit test suite.

Test fixtures must use placeholder hostnames per **Placeholder Hostnames** below. A repro captured against a live host gets sanitized before it becomes a test.

## Placeholder Hostnames

Never commit a real hostname, environment ID, tenant ID, or account identifier — not in source, tests, docs, skills, issues, or PR descriptions. This includes internal hosts from whatever environment you reproduced a bug in.

**Self-hosted / on-premise services** use `<service>.imagile.dev`:

`jira.imagile.dev`, `bitbucket.imagile.dev`, `confluence.imagile.dev`, `sonar.imagile.dev`, `jenkins.imagile.dev`, `artifactory.imagile.dev`, `dynatrace.imagile.dev`, `ucd.imagile.dev`, `sde.imagile.dev`, `tfs.imagile.dev`, `ado.imagile.dev`, `iq.imagile.dev`, `ghe.imagile.dev`

**Vendor-hosted SaaS** keeps the vendor domain, with `imagile` as the tenant: `imagile.service-now.com`, `imagile.sdelements.com`, `abc12345.live.dynatrace.com`, `eu.ast.checkmarx.net`.

**Opaque IDs** (tenant, realm, environment, org): `imagile` where a name reads naturally, `abc12345` for short IDs, `abc12345-0000-0000-0000-000000000000` for UUID-shaped values.

Do not use `example.com`, `company.com`, `mycompany.com`, `your-company.com`, or `examplecompany.net`. The last four are real domains registered to third parties — a user who copy-pastes one into `baseUrl` sends their credentials to someone else's host.

**Exception — email addresses.** Email placeholders keep `you@example.com`. `example.com` is RFC 2606 reserved and is the conventional placeholder for an address field; `you@imagile.dev` would wrongly imply the user's mailbox lives on the maintainer's domain. This rule covers service hostnames, not email.

**Exception:** tests asserting behavior against a *foreign* host (rejecting a mismatched git remote, cross-origin checks) must use a visibly different domain. `src/lib/git-context.test.ts` keeps `other.example.com` for exactly this reason — using `imagile.dev` on both sides would defeat the test.

**Constraint — never add wildcard DNS to `imagile.dev`.** These placeholders are safe because `*.imagile.dev` does not resolve, so a copy-pasted config fails at DNS before pncli sends any auth header. A wildcard A/CNAME record would silently turn every published example into a credential-collection endpoint. If a wildcard ever becomes necessary, migrate these docs to a reserved RFC 2606 domain first.

## Commit Conventions

Use Conventional Commits: `fix:` (patch), `feat:` (minor), `feat!:` (breaking/major).
Expand Down
6 changes: 3 additions & 3 deletions pncli-scaffold-prompt.md
Original file line number Diff line number Diff line change
Expand Up @@ -234,11 +234,11 @@ Owned by the individual developer. Contains auth credentials and server URLs. NO
{
"jira": {
"baseUrl": "https://your-domain.atlassian.net",
"email": "you@company.com",
"email": "you@example.com",
"apiToken": "your-jira-api-token"
},
"bitbucket": {
"baseUrl": "https://bitbucket.your-company.com",
"baseUrl": "https://bitbucket.imagile.dev",
"pat": "your-bitbucket-pat"
},
"defaults": {
Expand Down Expand Up @@ -343,7 +343,7 @@ Error shape:

- Detect repo root via `git rev-parse --show-toplevel`
- Parse Bitbucket project/repo from first remote matching the configured `bitbucket.baseUrl`
- Parse both SSH (`git@bitbucket.company.com:7999/PROJ/repo.git`) and HTTPS (`https://bitbucket.company.com/scm/PROJ/repo.git`) remote formats
- Parse both SSH (`git@bitbucket.imagile.dev:7999/PROJ/repo.git`) and HTTPS (`https://bitbucket.imagile.dev/scm/PROJ/repo.git`) remote formats
- Get current branch via `git rev-parse --abbrev-ref HEAD`
- All git operations use `child_process.execSync` with `{ encoding: 'utf8', cwd: repoRoot }`
- Handle "not a git repo" gracefully — return null, don't throw
Expand Down
6 changes: 3 additions & 3 deletions skills/pncli/ado.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ Enables: `pncli ado workitem`, `pncli ado repo`, `pncli ado repo create`, `pncli

| Key | Env var | Description |
|-----|---------|-------------|
| `ado.baseUrl` | `PNCLI_ADO_BASE_URL` | ADO Server root, e.g. `https://tfs.company.com` |
| `ado.baseUrl` | `PNCLI_ADO_BASE_URL` | ADO Server root, e.g. `https://tfs.imagile.dev` |
| `ado.pat` | `PNCLI_ADO_PAT` | Personal access token |

## Config file (persistent)

```
pncli config set ado.baseUrl https://tfs.company.com
pncli config set ado.baseUrl https://tfs.imagile.dev
pncli config set ado.pat <token>
pncli config set defaults.ado.collection DefaultCollection
pncli config set defaults.ado.project MyProject
Expand All @@ -21,7 +21,7 @@ pncli config set defaults.ado.project MyProject
## Env vars (ephemeral / CI)

```
export PNCLI_ADO_BASE_URL=https://tfs.company.com
export PNCLI_ADO_BASE_URL=https://tfs.imagile.dev
export PNCLI_ADO_PAT=<token>
```

Expand Down
6 changes: 3 additions & 3 deletions skills/pncli/artifactory.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Enables: `pncli artifactory repo`, `pncli artifactory package` — list reposito

| Key | Env var | Description |
|-----|---------|-------------|
| `artifactory.baseUrl` | `PNCLI_ARTIFACTORY_BASE_URL` | Artifactory root, e.g. `https://artifactory.company.com` |
| `artifactory.baseUrl` | `PNCLI_ARTIFACTORY_BASE_URL` | Artifactory root, e.g. `https://artifactory.imagile.dev` |
| `artifactory.token` | `PNCLI_ARTIFACTORY_TOKEN` | Identity token or API key |

## Optional — virtual repo names
Expand All @@ -20,7 +20,7 @@ Enables: `pncli artifactory repo`, `pncli artifactory package` — list reposito
## Config file (persistent)

```
pncli config set artifactory.baseUrl https://artifactory.company.com
pncli config set artifactory.baseUrl https://artifactory.imagile.dev
pncli config set artifactory.token <token>
pncli config set artifactory.npmRepo npm-virtual
pncli config set artifactory.nugetRepo nuget-virtual
Expand All @@ -30,6 +30,6 @@ pncli config set artifactory.mavenRepo maven-virtual
## Env vars (ephemeral / CI)

```
export PNCLI_ARTIFACTORY_BASE_URL=https://artifactory.company.com
export PNCLI_ARTIFACTORY_BASE_URL=https://artifactory.imagile.dev
export PNCLI_ARTIFACTORY_TOKEN=<token>
```
6 changes: 3 additions & 3 deletions skills/pncli/bitbucket.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,20 @@ Enables: `pncli bitbucket create-repo`, `pncli bitbucket list-prs`, `pncli bitbu

| Key | Env var | Description |
|-----|---------|-------------|
| `bitbucket.baseUrl` | `PNCLI_BITBUCKET_BASE_URL` | Bitbucket Server root, e.g. `https://bitbucket.company.com` |
| `bitbucket.baseUrl` | `PNCLI_BITBUCKET_BASE_URL` | Bitbucket Server root, e.g. `https://bitbucket.imagile.dev` |
| `bitbucket.pat` | `PNCLI_BITBUCKET_PAT` | Personal access token |

## Config file (persistent)

```
pncli config set bitbucket.baseUrl https://bitbucket.company.com
pncli config set bitbucket.baseUrl https://bitbucket.imagile.dev
pncli config set bitbucket.pat <token>
```

## Env vars (ephemeral / CI)

```
export PNCLI_BITBUCKET_BASE_URL=https://bitbucket.company.com
export PNCLI_BITBUCKET_BASE_URL=https://bitbucket.imagile.dev
export PNCLI_BITBUCKET_PAT=<token>
```

Expand Down
6 changes: 3 additions & 3 deletions skills/pncli/checkmarx.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Enables: `pncli checkmarx project list/get`, `pncli checkmarx scan list/get/stat
| Key | Env var | Description |
|-----|---------|-------------|
| `checkmarx.baseUrl` | `PNCLI_CHECKMARX_BASE_URL` | Checkmarx One API base, e.g. `https://ast.checkmarx.net/api` |
| `checkmarx.tenantName` | `PNCLI_CHECKMARX_TENANT_NAME` | IAM realm / tenant name, e.g. `mycompany` |
| `checkmarx.tenantName` | `PNCLI_CHECKMARX_TENANT_NAME` | IAM realm / tenant name, e.g. `imagile` |
| `checkmarx.apiKey` | `PNCLI_CHECKMARX_API_KEY` | API key created in Checkmarx One IAM (recommended) |
| `checkmarx.clientId` | `PNCLI_CHECKMARX_CLIENT_ID` | OAuth2 client ID (alternative to API key) |
| `checkmarx.clientSecret` | `PNCLI_CHECKMARX_CLIENT_SECRET` | OAuth2 client secret (alternative to API key) |
Expand All @@ -19,15 +19,15 @@ short-lived bearer token automatically. No external tools are required.

```
pncli config set checkmarx.baseUrl https://ast.checkmarx.net/api
pncli config set checkmarx.tenantName mycompany
pncli config set checkmarx.tenantName imagile
pncli config set checkmarx.apiKey <api-key>
```

## Env vars (ephemeral / CI)

```
export PNCLI_CHECKMARX_BASE_URL=https://ast.checkmarx.net/api
export PNCLI_CHECKMARX_TENANT_NAME=mycompany
export PNCLI_CHECKMARX_TENANT_NAME=imagile
export PNCLI_CHECKMARX_API_KEY=<api-key>
```

Expand Down
6 changes: 3 additions & 3 deletions skills/pncli/confluence.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,20 @@ Enables: `pncli confluence get-page`, `create-page`, `update-page`, `delete-page

| Key | Env var | Description |
|-----|---------|-------------|
| `confluence.baseUrl` | `PNCLI_CONFLUENCE_BASE_URL` | Confluence server root, e.g. `https://confluence.company.com` |
| `confluence.baseUrl` | `PNCLI_CONFLUENCE_BASE_URL` | Confluence server root, e.g. `https://confluence.imagile.dev` |
| `confluence.apiToken` | `PNCLI_CONFLUENCE_API_TOKEN` | Personal access token |

## Config file (persistent)

```
pncli config set confluence.baseUrl https://confluence.company.com
pncli config set confluence.baseUrl https://confluence.imagile.dev
pncli config set confluence.apiToken <token>
```

## Env vars (ephemeral / CI)

```
export PNCLI_CONFLUENCE_BASE_URL=https://confluence.company.com
export PNCLI_CONFLUENCE_BASE_URL=https://confluence.imagile.dev
export PNCLI_CONFLUENCE_API_TOKEN=<token>
```

Expand Down
2 changes: 1 addition & 1 deletion skills/pncli/contrast.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ All four credential keys are found in your Contrast account under **User Setting

**Base URL examples:**
- Cloud SaaS: `https://app.contrastsecurity.com`
- On-premise: `https://contrast.company.com`
- On-premise: `https://contrast.imagile.dev`

## Config file (persistent)

Expand Down
10 changes: 5 additions & 5 deletions skills/pncli/jenkins.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Enables: `pncli jenkins build`, `pncli jenkins job` — list builds, get build s

| Key | Env var | Description |
|-----|---------|-------------|
| `jenkins.baseUrl` | `PNCLI_JENKINS_BASE_URL` | Jenkins root, e.g. `https://jenkins.company.com` |
| `jenkins.baseUrl` | `PNCLI_JENKINS_BASE_URL` | Jenkins root, e.g. `https://jenkins.imagile.dev` |
| `jenkins.username` | `PNCLI_JENKINS_USERNAME` | Jenkins username |
| `jenkins.apiToken` | `PNCLI_JENKINS_API_TOKEN` | API token (generated in Jenkins → User → Configure → API Token) |

Expand All @@ -15,15 +15,15 @@ pncli authenticates using HTTP Basic (username + API token).
## Config file (persistent)

```
pncli config set jenkins.baseUrl https://jenkins.company.com
pncli config set jenkins.baseUrl https://jenkins.imagile.dev
pncli config set jenkins.username <username>
pncli config set jenkins.apiToken <token>
```

## Env vars (ephemeral / CI)

```
export PNCLI_JENKINS_BASE_URL=https://jenkins.company.com
export PNCLI_JENKINS_BASE_URL=https://jenkins.imagile.dev
export PNCLI_JENKINS_USERNAME=<username>
export PNCLI_JENKINS_API_TOKEN=<token>
```
Expand All @@ -36,7 +36,7 @@ Teams with different Jenkins controllers per repo can set `defaults.jenkins.base
{
"defaults": {
"jenkins": {
"baseUrl": "https://jenkins.myteam.company.com"
"baseUrl": "https://jenkins.myteam.imagile.dev"
}
}
}
Expand All @@ -45,7 +45,7 @@ Teams with different Jenkins controllers per repo can set `defaults.jenkins.base
Or via the CLI:

```
pncli config set --repo defaults.jenkins.baseUrl https://jenkins.myteam.company.com
pncli config set --repo defaults.jenkins.baseUrl https://jenkins.myteam.imagile.dev
```

Resolution order (highest to lowest): project `.pncli.json` → global config → `PNCLI_JENKINS_BASE_URL` env var.
6 changes: 3 additions & 3 deletions skills/pncli/jira.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,20 @@ Enables: `pncli jira get-issue`, `create-issue`, `update-issue`, `search`, `list

| Key | Env var | Description |
|-----|---------|-------------|
| `jira.baseUrl` | `PNCLI_JIRA_BASE_URL` | Jira server root, e.g. `https://jira.company.com` |
| `jira.baseUrl` | `PNCLI_JIRA_BASE_URL` | Jira server root, e.g. `https://jira.imagile.dev` |
| `jira.apiToken` | `PNCLI_JIRA_API_TOKEN` | Personal access token |

## Config file (persistent)

```
pncli config set jira.baseUrl https://jira.company.com
pncli config set jira.baseUrl https://jira.imagile.dev
pncli config set jira.apiToken <token>
```

## Env vars (ephemeral / CI)

```
export PNCLI_JIRA_BASE_URL=https://jira.company.com
export PNCLI_JIRA_BASE_URL=https://jira.imagile.dev
export PNCLI_JIRA_API_TOKEN=<token>
```

Expand Down
2 changes: 1 addition & 1 deletion skills/pncli/marketplace.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Use `--branch main` if the default branch is `main` instead of `master`. Use `--

**Example:**
```
pncli skills marketplace add https://bitbucket.company.com/scm/ai/skills.git --name internal-ai
pncli skills marketplace add https://bitbucket.imagile.dev/scm/ai/skills.git --name internal-ai
```

You can register as many marketplaces as you like — just run `add` again with a different URL. `marketplace setup` is kept as an alias of `add` for backward compatibility.
Expand Down
8 changes: 4 additions & 4 deletions skills/pncli/openshift.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ No `kubectl` or `oc` CLI is required.

| Key | Env var | Description |
|-----|---------|-------------|
| `openshift.baseUrl` | `PNCLI_OPENSHIFT_BASE_URL` | API server URL, e.g. `https://api.cluster.example.com:6443` |
| `openshift.baseUrl` | `PNCLI_OPENSHIFT_BASE_URL` | API server URL, e.g. `https://api.cluster.imagile.dev:6443` |
| `openshift.token` | `PNCLI_OPENSHIFT_TOKEN` | Service account bearer token |

## Getting your service account token
Expand All @@ -20,22 +20,22 @@ cat /var/run/secrets/kubernetes.io/serviceaccount/token
**Via OpenShift REST API** (using an existing token):
```bash
curl -H "Authorization: Bearer $EXISTING_TOKEN" \
https://api.cluster.example.com:6443/api/v1/namespaces/my-ns/serviceaccounts/default/token \
https://api.cluster.imagile.dev:6443/api/v1/namespaces/my-ns/serviceaccounts/default/token \
-X POST -H 'Content-Type: application/json' \
-d '{"apiVersion":"authentication.k8s.io/v1","kind":"TokenRequest","spec":{"expirationSeconds":3600}}'
```

## Set via env vars (ephemeral)

```bash
export PNCLI_OPENSHIFT_BASE_URL=https://api.cluster.example.com:6443
export PNCLI_OPENSHIFT_BASE_URL=https://api.cluster.imagile.dev:6443
export PNCLI_OPENSHIFT_TOKEN=eyJhbGciOiJSUzI1NiI...
```

## Set via config file (persistent)

```bash
pncli config set openshift.baseUrl https://api.cluster.example.com:6443
pncli config set openshift.baseUrl https://api.cluster.imagile.dev:6443
pncli config set openshift.token eyJhbGciOiJSUzI1NiI...
```

Expand Down
6 changes: 3 additions & 3 deletions skills/pncli/sde.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,18 @@ Enables: `pncli sde task` — list threat model tasks and their compliance statu
|-----|---------|-------------|
| `sde.connection` | `PNCLI_SDE_CONNECTION` | Connection string in the format `token@hostname` |

The connection string combines your API token and the SDElements hostname into a single value, e.g. `mytoken@sde.company.com`.
The connection string combines your API token and the SDElements hostname into a single value, e.g. `mytoken@sde.imagile.dev`.

## Config file (persistent)

```
pncli config set sde.connection mytoken@sde.company.com
pncli config set sde.connection mytoken@sde.imagile.dev
```

## Env vars (ephemeral / CI)

```
export PNCLI_SDE_CONNECTION=mytoken@sde.company.com
export PNCLI_SDE_CONNECTION=mytoken@sde.imagile.dev
```

## Repo defaults
Expand Down
6 changes: 3 additions & 3 deletions skills/pncli/servicenow.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Enables: `pncli servicenow change`, `pncli servicenow incident` — list and get

| Key | Env var | Description |
|-----|---------|-------------|
| `servicenow.baseUrl` | `PNCLI_SERVICENOW_BASE_URL` | Instance root, e.g. `https://mycompany.service-now.com` |
| `servicenow.baseUrl` | `PNCLI_SERVICENOW_BASE_URL` | Instance root, e.g. `https://imagile.service-now.com` |
| `servicenow.username` | `PNCLI_SERVICENOW_USERNAME` | ServiceNow username |

### Auth — password or API token (one required)
Expand All @@ -19,15 +19,15 @@ Enables: `pncli servicenow change`, `pncli servicenow incident` — list and get
## Config file (persistent)

```
pncli config set servicenow.baseUrl https://mycompany.service-now.com
pncli config set servicenow.baseUrl https://imagile.service-now.com
pncli config set servicenow.username <username>
pncli config set servicenow.password <password>
```

## Env vars (ephemeral / CI)

```
export PNCLI_SERVICENOW_BASE_URL=https://mycompany.service-now.com
export PNCLI_SERVICENOW_BASE_URL=https://imagile.service-now.com
export PNCLI_SERVICENOW_USERNAME=<username>
export PNCLI_SERVICENOW_PASSWORD=<password>
```
6 changes: 3 additions & 3 deletions skills/pncli/sonarqube.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,20 @@ Enables: `pncli sonar issue`, `pncli sonar project` — list code quality and se

| Key | Env var | Description |
|-----|---------|-------------|
| `sonar.baseUrl` | `PNCLI_SONAR_BASE_URL` | SonarQube server root, e.g. `https://sonar.company.com` |
| `sonar.baseUrl` | `PNCLI_SONAR_BASE_URL` | SonarQube server root, e.g. `https://sonar.imagile.dev` |
| `sonar.token` | `PNCLI_SONAR_TOKEN` | User token (generated in SonarQube → My Account → Security) |

## Config file (persistent)

```
pncli config set sonar.baseUrl https://sonar.company.com
pncli config set sonar.baseUrl https://sonar.imagile.dev
pncli config set sonar.token <token>
```

## Env vars (ephemeral / CI)

```
export PNCLI_SONAR_BASE_URL=https://sonar.company.com
export PNCLI_SONAR_BASE_URL=https://sonar.imagile.dev
export PNCLI_SONAR_TOKEN=<token>
```

Expand Down
6 changes: 3 additions & 3 deletions skills/pncli/sonatypeiq.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Enables: `pncli sonatypeiq applications`, `pncli deps frisk --source sonatypeiq`

| Key | Env var | Description |
|-----|---------|-------------|
| `sonatypeiq.baseUrl` | `PNCLI_SONATYPEIQ_BASE_URL` | IQ Server root, e.g. `https://iq.company.com` |
| `sonatypeiq.baseUrl` | `PNCLI_SONATYPEIQ_BASE_URL` | IQ Server root, e.g. `https://iq.imagile.dev` |
| `sonatypeiq.userCode` | `PNCLI_SONATYPEIQ_USER_CODE` | User Token code (from User Menu → User Token) |
| `sonatypeiq.passcode` | `PNCLI_SONATYPEIQ_PASSCODE` | User Token passcode (from User Menu → User Token) |

Expand All @@ -15,15 +15,15 @@ The `userCode` and `passcode` are User Token credentials, not your login passwor
## Config file (persistent)

```
pncli config set sonatypeiq.baseUrl https://iq.company.com
pncli config set sonatypeiq.baseUrl https://iq.imagile.dev
pncli config set sonatypeiq.userCode <user-code>
pncli config set sonatypeiq.passcode <passcode>
```

## Env vars (ephemeral / CI)

```
export PNCLI_SONATYPEIQ_BASE_URL=https://iq.company.com
export PNCLI_SONATYPEIQ_BASE_URL=https://iq.imagile.dev
export PNCLI_SONATYPEIQ_USER_CODE=<user-code>
export PNCLI_SONATYPEIQ_PASSCODE=<passcode>
```
Expand Down
Loading
Loading