Skip to content

Releases: 1273984347/dsh-github-gate

v2.1.0 — the gates now run in CI, and each one is proven able to fail

Choose a tag to compare

@1273984347 1273984347 released this 20 Oct 00:22

Makes the verification real: the gates now run in CI, and every one is proven able to fail.

The defect this fixes

verify-bundle.mjs caught three real packaging omissions in three days — install.ps1/install.sh, PRIVACY.md and docs/roadmap.md were each present in the tree and absent from manifest.files, so the tarball would have shipped without them.

All three were caught locally, by hand. CI never ran that script: it imports index.js, which needs a local DSH installation, so the whole file was skipped — including the static packaging checks that need nothing but the tree. CI's own "Manifest files exist" step only checks six fixed paths, not that files is complete. The badge stayed green while the package was incomplete.

What changed

Split along the dependency line, not the topic line.

  • tools/verify-manifest.mjs — Node builtins only; owns every static check and runs in CI. One implementation, referenced by verify-bundle.mjs.
  • tools/verify-bundle.mjs — 569 → ~200 lines; keeps only checks that must load the plugin, and reports UNVERIFIED rather than PASS where it cannot look.
  • tools/lib/report.mjs — one three-state reporter (pass/fail/unverified), so a check that could not run never reads as success, and tests can assert state instead of parsing console output.

tools/check-script-coverage.mjs catches the class, not the instance. Every tools/ script must be referenced by scripts, CI, tests or another tool — or listed in docs/script-baseline.json with a reason (≥20 characters; an exemption that is no longer needed is itself a failure). Its first run found four unreferenced scripts and five gates missing from CI.

Documented numbers are now measured. docs/stats.json + tools/status.mjs --write physically run each measurement and record the source; the README carries 61<!--stats:action_count--> claims that tools/check-docs.mjs verifies. Its first run found two wrong numbers in the README:

Claim Actual
9 tools / 58 actions 61
23 destructive actions 29 (+4 github_api write methods, classified at run time)

Two new test suites (32 tests)

  • test/wiring.test.mjs — asserts gates appear inside CI run: blocks, not step names, because a step named "Static delivery gate" whose body is echo skipped satisfies any name-based check. It caught that npm run release did not run the new static gates.
  • test/gates.test.mjs — builds a genuinely broken tree per gate and asserts the matching result is FAIL, because "exit code ≠ 0" passes when the wrong check failed.

Verification

Suite Result
Offline tests 207/207 (32 new)
Static gates 4/4 (manifest / coverage / docs / encoding)
Full dynamic gate passing
Parameters / guidance / snapshots / argv 211/211 · 114/114 · 180/180 · 84/84

Note on scope

No tool behaviour changed — this release is entirely about whether the project can tell when it is wrong.

Full Changelog: v2.0.0...v2.1.0

v2.0.0 — renamed to dsh-github-gate, and the product surface it was missing

Choose a tag to compare

@1273984347 1273984347 released this 18 Oct 23:59

Renamed to dsh-github-gate. A plugin called dsh-github-toolkit already exists with the same topics and is more product-complete; in a marketplace we looked like a less-featured copy of it. The new name keeps "github" (searchable) and names the actual differentiator: every state-changing action goes through a gate.

Tool names (github_*) and actions are unchanged — only the package identity changed.

What this release adds

Settings → Plugins → GitHub. A real page, not YAML editing:

  • shows whether a credential is configured and which layer supplied it
  • a password field that writes the PAT to the Harness credential store
  • Test connection — one real gh api user round trip through the same chain the tools use
  • cannot read the token back: the Host never returns it, and the field clears on save
  • all three routes requireGate and fail closed (403) when no connection service can judge the caller — a page that writes a secret must not be reachable by an unjudged caller

One failure vocabulary (lib/format.js). 401, 403 quota, 403 SAML, missing scope, 404, 422, 409, network and missing-gh each name the fix. An unrecognised failure gets no hint rather than a generic sentence — generic hints train readers to skip hints.

One-command download. install.ps1 / install.sh fetch the release, verify its sha256 against the digest GitHub publishes, and print the install path. They deliberately do not install: that step belongs to the plugin manager, which asks for approval.

Repository furniture. Bug/feature issue forms whose fields mirror this plugin's own diagnostics; a PR template that asks which behaviour contract applies; dependabot for Actions; and a tag-driven release workflow that checks the tag matches package.json before packing the same tarball a user installs.

PRIVACY.md and docs/roadmap.md — the latter records what is not planned and why.

Verification

Suite Result
Offline tests 176/176 (18 new)
Parameter coverage 211/211 across 9 tools
Behaviour snapshots 180/180 deterministic
argv shapes parsed by real gh 84/84
Guidance / bundle / encoding all clean
install.ps1 against this release downloaded 235 KB, sha256 matched

The 18 new tests cover the two places Node's test runner cannot reach on its own: the HTTP routes (fail-closed admission, no token echo, real API call) and the browser half (loaded through a fake __ModuleLoader__, both slots register, both components return an element tree instead of throwing).

Install

irm https://raw.githubusercontent.com/1273984347/dsh-github-gate/main/install.ps1 | iex

Then plugin_manager action install_bundle with the printed path.

If you installed the old name, uninstall dsh-github-toolkit first — the package identity changed.

Full Changelog: v1.7.1...v2.0.0

v1.7.1 — correct the restart claim (measurement disproved it)

Choose a tag to compare

@1273984347 1273984347 released this 18 Oct 23:04

Corrects a sentence in 1.7.0 that measurement disproved.

What was wrong

1.7.0 said: "a restart is required before the new version actually runs" — and the injected prompt told the model never to claim the new version is active before that restart.

Installing 1.7.0 over 1.6.1 showed both are wrong for this install path. Immediately after install_bundle returned application: applied, with no process restart:

Check 1.6.1 Observed
github_* tools live 8 9 (including github_update, 4 params)
projected Config schema no updateCheck has updateCheck / updateRepo / updateChannel / updateCacheDir
prompt section rules 6 7

All three exist only in the new generation, so the plugin manager re-activated the entry and the new code was already serving.

The opposite was also measured earlier in the same environment (installing 0.2.0 did not update the projected Config schema until a restart). Two opposite observations mean the boolean was never a fact — and a confident wrong guess is worse than a question, especially in a prompt that then makes the model deny a version which is already live.

What changed

next.restartRequired: true   →   "unverified"
  • stage now says one step remains (install) and asks the caller to verify the running generation with a tool or Config key unique to the new version.
  • The installed package.json is called out as not proof: pnpm replaces it before the module is necessarily reloaded, so pluginVersion() can report the new version while the old code runs.
  • Prompt rule 7 compressed to stay inside the 2400-character budget; README and CHANGELOG corrected.

New test pins restartRequired === 'unverified' and the verification guidance; the live probe asserts the same.

Verification

158 offline tests · 211/211 parameter coverage · 114/114 guidance · 84/84 argv shapes by real gh · 180 deterministic snapshots · live update probe passing.

v1.7.0 — auto-update: check and stage, install stays with the platform

Choose a tag to compare

@1273984347 1273984347 released this 18 Oct 22:57

Adds github_update: check reports whether a newer release exists, stage downloads it and verifies its sha256 against the digest GitHub publishes.

What it does — and deliberately does not do

check   → is there a newer release?              read-only
stage   → download it and verify its digest      writes one file
install → plugin_manager install_bundle          platform, approval-gated
restart → you                                    platform

Three measured constraints put installation and the restart outside this plugin:

  • Node's fetch cannot reach github.com on a TLS-intercepted host (UNABLE_TO_VERIFY_LEAF_SIGNATURE while gh succeeds), so every network call goes through gh — the same reason github_api routes through gh api.
  • A replaced bundle needs a restart. Node has already imported the old module generation; writing new files changes nothing until the Host restarts.
  • Installation is owned by the plugin manager. install_bundle rewrites the profile's package.json, prunes node_modules, and applies the patch row. A plugin editing the profile itself would desynchronise those and bypass the approval step that gates running downloaded code.

So stage returns a path and states installed: false, next.restartRequired: true.

Details

  • The digest is checked, and "no digest" is not "verified". Three outcomes — match, mismatch, unverified. A mismatch refuses to stage and prints both hashes. An intact staged copy is reused unless force: true.
  • unknown is its own answer. An unparseable version pair is never reported as "up to date", and a source checkout that is ahead of every release is told so instead of being offered a downgrade.
  • updateCheck: true (default false) adds a cached 24-hour startup notice. Off by default: an activation-time network call is a surprise.

Verification

Suite Result
Offline tests 157/157 (17 new)
Parameter coverage 211/211 across 9 tools
Behaviour snapshots 180/180 deterministic
argv shapes parsed by real gh 84/84
Live end-to-end against the real release 11/11 — read, download, digest match, reuse, tamper detection

The live probe (npm run probe:update) downloads the real 203 KB asset, verifies its digest against GitHub's published sha256:1b2c234e…, and catches a one-byte tamper as mismatch.

New config keys: updateCheck, updateRepo, updateChannel, updateCacheDir.

Full detail in CHANGELOG.md.

v1.6.3 — first open-source release

Choose a tag to compare

@1273984347 1273984347 released this 18 Oct 22:46

First open-source release. A GitHub toolkit for DeepSeek Harness: eight typed github_* tools over the GitHub CLI, a layered credential chain with Device Flow authorization, workspace-bound repository detection, and a guarded raw REST escape hatch.

Install

Download dsh-github-toolkit-1.6.3.tgz below and point the Harness plugin manager (plugin_manager action install_bundle) at the unpacked package directory. Do not install a link: to the source tree — the launcher's runtime resolution does not reach bare @deepseek-ai/* imports through a junction, and the plugin then fails with ERR_MODULE_NOT_FOUND.

Requires DSH >=0.2.0-0 <0.3.0 and the GitHub CLI (gh) on PATH.

What it provides

Tool Covers
github_auth Credential chain status, end-to-end connectivity probe, Device Flow login, PAT login, logout
github_repo View, list, branches, clone, create, edit, rename, archive, delete
github_pr List, view, diff, checks, status, create, comment, review, ready, checkout, merge, close, reopen, edit
github_issue List, view, create, comment, close, reopen, edit, develop
github_release List, view, create, edit, upload, download, delete
github_actions Run list/view/log/watch/rerun/cancel/delete, workflow list/view/dispatch
github_search Repositories, issues, pull requests, code, commits
github_api Guarded raw REST for everything else (opt-in via allowRawApi)

Also: a prompt section, three on-demand skills (github-pr-review, github-ci-triage, github-issue-to-pr), and a session-header branch pill.

Safety model

  • Every command is an argv array spawned with shell: false — model-supplied text is never re-interpreted as shell syntax.
  • Every action that changes remote state is classified destructive: 23 of them, each requiring confirm: true and passing an approval seam. confirm is the model's intent, not the user's consent.
  • github_api write methods are classified at run time by their method, so the escape hatch cannot skip the gate.
  • Secrets never enter argv. Device Flow talks only to github.com, with no broker and no secret on disk.
  • Bounded processes (timeout → SIGTERM → SIGKILL) and bounded output (one byte budget across stdout+stderr, spilling to a file).

Verification

  • 140 offline tests, 203/203 declared-parameter coverage
  • 176 behaviour snapshots pinning exact argv and result values
  • 80/80 argv shapes parsed by a real gh --help; 50/50 positional arities matched against gh's own USAGE text
  • Bundle integrity, prompt/skill guidance, and encoding all gated in npm run release

Full history in CHANGELOG.md; design decisions and the defects that shaped them in docs/DESIGN.md.

MIT licensed.