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
59 changes: 27 additions & 32 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,54 +7,49 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [0.15.0] - 2026-05-27

### Security

- **BREAKING:** `apm install` against a `*.ghe.com` marketplace now refuses bare cross-repo `repo:` fields in `marketplace.json` before any network request runs, closing a dependency-confusion attack vector. Previously a bare `repo: owner/repo` on an enterprise marketplace could silently resolve to an attacker-controlled namespace on public `github.com`; the install now fail-closes with an actionable error. Qualify the `repo:` field to fix:
- **BREAKING:** `apm install` against a `*.ghe.com` marketplace now refuses bare cross-repo `repo:` fields in `marketplace.json` before any network request runs, closing a dependency-confusion attack vector where `repo: owner/repo` could silently resolve to an attacker-controlled namespace on public `github.com`. Qualify with `corp.ghe.com/owner/repo` for same-host enterprise deps or `github.com/owner/repo` for declared cross-host deps. (closes #1326) -- by @edenfunf (#1459)

```yaml
# Before (ambiguous -- refused on enterprise marketplaces):
source:
type: git
repo: owner/repo

# After -- enterprise dep on the same host:
source:
type: git
repo: corp.ghe.com/owner/repo

# After -- declared cross-host dep on public github.com:
source:
type: git
repo: github.com/owner/repo
```
### Added

(closes #1326) -- by @edenfunf (#1459)
- `GitCache` now disables git hooks (`core.hooksPath=/dev/null`) and skips submodule recursion on every clone, fetch, and checkout. Hardens APM against malicious upstreams, which is on-path for the new generic-git marketplace support.
- `apm config set prefer-ssh true` / `apm config set allow-protocol-fallback true` persist transport preferences to `~/.apm/config.json` so SSH-only and corporate GHES users stop re-passing `--ssh` / `--allow-protocol-fallback` on every `apm install`. Resolution order: CLI flag > env var > `apm config` > default. (closes #1243, #1308)
- Experimental package registry resolver and `apm-policy.yml` source-mandate enforcement -- controlled sources, locked versions, byte-level SHA-256 verification. Git-based dependencies unchanged. Enable with `apm experimental enable registries`; configure per-registry credentials via `apm config set registry.<name>.{url,token}`; mandate via `registry_source: {require: [...], allow_non_registry: false}`. Package signing, SBOM, and SLSA provenance are out of scope for v1. (#1471)
- `marketplace.packages[].source` in `apm.yml` accepts non-default git hosts via the `host.tld/owner/repo` shorthand or the full `https://host.tld/owner/repo[.git]` URL for `apm pack`, unlocking GitHub Enterprise and self-hosted GitLab as first-class marketplace package sources. (#1288)
- `apm marketplace add` now accepts local filesystem paths, `file://` URIs, SSH URLs, and HTTPS URLs to any git host (Azure DevOps via `ADO_APM_PAT`, GitLab, Gitea, Bitbucket Server, self-hosted). Generic-git registrations fetch `marketplace.json` via `GitCache` and never forward APM tokens; local marketplaces read the manifest directly. Same change hardens `GitCache` against malicious upstreams: every clone/fetch/checkout sets `core.hooksPath=/dev/null` and skips submodule recursion. (#1476)

### Added
### Changed

- `apm compile` internals: deduplicated compilation config and registry-cursor refactor; no user-visible behaviour change but reduces drift between paths. (#1367)
- `triage-panel` skill: replace invalid `difc:` block with `tools.github.min-integrity` so the gh-aw workflow lints clean and integrity gating actually applies. (#1487)
- `triage-panel` skill: DIFC read-integrity exemption for external issues so triage can read community-reported issue bodies without the gate blocking. (#1462)
- CodeQL integration tests now assert on parsed URL components instead of substrings, removing a class of false-positive matches and matching the repo test convention. (#1492)

### Performance

- `apm config set prefer-ssh true` / `apm config set allow-protocol-fallback true` persist transport preferences to `~/.apm/config.json` so SSH-only and corporate GHES users no longer need to re-pass `--ssh` / `--allow-protocol-fallback` (or export env vars in shell profiles) on every `apm install`. Resolution order: CLI flag > `APM_GIT_PROTOCOL` / `APM_ALLOW_PROTOCOL_FALLBACK` env var > `apm config` > built-in default. `apm config unset prefer-ssh` and `apm config unset allow-protocol-fallback` remove the persisted value. (#1243)
- `apm pack --marketplace=FORMATS` filters which marketplace formats are built in a single run; accepts comma-separated names and sentinels `all`/`none`. (#1317)
- `apm pack --marketplace-path FORMAT=PATH` overrides the output path for a specific marketplace format at invocation time. Env var overrides (`APM_MARKETPLACE_<FORMAT>_PATH`) are planned for v0.15. (#1317)
- `apm pack --json` emits a stable JSON contract to stdout (`{ok, dry_run, warnings, errors, marketplace: {outputs: [{format, path, ...}]}}`); all logs move to stderr so downstream tooling can `jq` the output safely. (#1317)
- `marketplace.outputs` in `apm.yml` now accepts a map form keyed by format name (`outputs: {claude: {}, codex: {path: ...}}`), replacing the deprecated list form; the list form still parses with a one-cycle deprecation warning. (#1317)
- `apm marketplace init` now scaffolds the explicit map-form `outputs: {claude: {}}` so the default state is observable in the manifest. (#1317)
- Add experimental registry resolver and `apm-policy.yml` source-mandate enforcement. Git-based dependencies are unchanged. Enable with `apm experimental enable registries`; configure per-registry credentials via `apm config set registry.<name>.{url,token}`; mandate registry usage in `apm-policy.yml` via `registry_source: {require: [...], allow_non_registry: false}`. Framing: APM dependency governance -- controlled sources, locked versions, and byte-level SHA-256 verification. Package signing, SBOM generation, and SLSA provenance are not included at v1.
- `marketplace.packages[].source` in `apm.yml` now accepts non-default git hosts via the `host.tld/owner/repo` shorthand or the full `https://host.tld/owner/repo[.git]` URL; per-host auth flows through the standard APM token chain. Unlocks GitHub Enterprise and self-hosted GitLab as first-class marketplace package sources. (#1288)
- `apm marketplace add` now accepts local filesystem paths, `file://` URIs, SSH URLs, and HTTPS URLs to any git host (Azure DevOps via `ADO_APM_PAT`, GitLab, Gitea, Bitbucket Server, self-hosted). Generic-git registrations fetch `marketplace.json` via `GitCache` and never forward APM tokens; local marketplaces read the manifest directly. `apm install <plugin>@<local-marketplace>` is fully supported, including marketplaces whose `marketplace.json` uses relative plugin sources.
- Scaling guards on variant-key and cache-lookup paths, wired into the CI integration gate so per-dep resolution regressions fail PRs instead of slipping to main. (#1439)

### Fixed

- `apm install` now re-resolves a dependency when its ref pin is changed in `apm.yml`; previously the locked commit always won, silently ignoring the edit -- by @sergio-sisternes-epam (#1473)
- `--refresh` flag on `apm install` now actually re-resolves all ref pins (previously accepted but had no effect) -- by @sergio-sisternes-epam (#1473)
- `apm install` re-resolves a dependency when its ref pin changes in `apm.yml` and `--refresh` actually re-resolves all pins (previously accepted but no-op) -- by @sergio-sisternes-epam (#1473)
- Copilot, Codex, Cursor, Claude, Windsurf, OpenCode, and Gemini adapters handle MCP v0.1 `runtimeArguments`/`packageArguments` with `variables` (no `type` key), matching the VS Code fix from #1444. (#1461, closes #1452, thanks @sergio-sisternes-epam)
- **Deduplicate Claude Code instructions.** `apm compile --target claude` now omits the "Project Standards" section from `CLAUDE.md` when instructions are already deployed to `.claude/rules/` by `apm install`, avoiding duplicate content in Claude Code's context window. `CLAUDE.md` is still generated for constitution and dependency imports. (#1138)
- `apm compile --target claude` omits the "Project Standards" section from `CLAUDE.md` when instructions are already deployed to `.claude/rules/` by `apm install`, avoiding duplicate content in Claude Code's context window. `CLAUDE.md` is still generated for constitution and dependency imports. (closes #1138, #1146)
- `apm compile --watch` now live-reloads `apm.yml` edits instead of caching the initial snapshot, and warns when combined with `--clean` so a watch session does not silently wipe state on every change. (#1403)
- Windows: `_local_path_from_source` handles `file://` URI shapes (drive-letter, UNC) so local marketplaces on Windows resolve correctly, and preserves POSIX separators on plain POSIX-shaped inputs (`Path().expanduser()` was rewriting `/home/user` to `\home\user`); local-path pass-through is now cross-platform. (#1484)
- `apm install` rewrites skill-shipped MCP `command` paths for the Claude target so portable installs resolve relative to `.claude/` instead of the source skill's checkout. (#1465)
- Unstuck 3 flaky integration tests that were intermittently blocking the merge queue. (#1477)

## [0.14.2] - 2026-05-22

### Added

- **Experimental:** `copilot-app` target scopes workflows to a real project row via loopback WS IPC (App running) or direct SQLite (App closed); `--global` workflow installs emit a one-time CWD-pivot warning. (#1431)
- `apm pack --marketplace=FORMATS` filters which marketplace formats build in a single run; accepts comma-separated names and `all`/`none` sentinels. (#1324)
- `apm pack --marketplace-path FORMAT=PATH` overrides the output path for a specific marketplace format at invocation time. (#1324)
- `apm pack --json` emits a stable JSON contract to stdout (`{ok, dry_run, warnings, errors, marketplace: {outputs: [...]}}`); all logs move to stderr so downstream tooling can `jq` the output. (#1324)
- `marketplace.outputs` in `apm.yml` accepts a map form keyed by format name (`outputs: {claude: {}, codex: {path: ...}}`), replacing the deprecated list form; the list form still parses with a one-cycle deprecation warning. `apm marketplace init` now scaffolds the explicit map form. (#1324)

### Changed

Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "apm-cli"
version = "0.14.2"
version = "0.15.0"
description = "MCP configuration tool"
readme = "README.md"
requires-python = ">=3.10"
Expand Down
2 changes: 1 addition & 1 deletion uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading