hy-2xeb: Install pipeline for GitHub-URL plugins (hy-gh-1)#9
Merged
Conversation
Extend src/core/plugin_install to support git sources. Parses GitHub URL forms (https with optional .git/#ref, github: shorthand, git@github.com SSH) plus generic git+/git:/ssh:/gitlab:/bitbucket:/file:// URLs through a new pure git_source parser. Adds --ref and --path CLI flags to the plugin install command; --ref conflicting with a URL #ref is rejected as source_ambiguous, and --path is reserved as git_subdir_unsupported. The fetch path clones with --filter=blob:none --no-checkout, checks out the requested ref (or the remote's HEAD symref by default), resolves HEAD to a commit, validates the manifest and entrypoint, refuses any symlinks in the artifact tree, then copies into an atomic install directory swap. Lock entries gain resolved_ref; the update probe runs git ls-remote and flips update.available when the upstream commit moved. Telemetry: the existing plugin.install span gains hyp_source_kind=git, git_url_host/owner/repo/ref/resolved_ref, content_hash, and manifest_hash. Child spans plugin.git.clone, plugin.git.checkout, plugin.git.resolve_ref, plugin.artifact.validate, and plugin.artifact.copy each carry status and error_kind. Git stderr is redacted for credentials before being surfaced. Tests cover URL parsing variants, the --ref/URL-fragment conflict, the subdir reservation, entrypoint traversal rejection, symlink detection, and content-hash stability. New hermetic smoke plugin_install_git_url builds a local bare repo and exercises the install end-to-end through the dispatcher. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
philcunliffe
added a commit
that referenced
this pull request
May 22, 2026
* chore: seed integration/github-install for feature flow * feat: install pipeline for GitHub-URL plugins (hy-2xeb) (#9) Extend src/core/plugin_install to support git sources. Parses GitHub URL forms (https with optional .git/#ref, github: shorthand, git@github.com SSH) plus generic git+/git:/ssh:/gitlab:/bitbucket:/file:// URLs through a new pure git_source parser. Adds --ref and --path CLI flags to the plugin install command; --ref conflicting with a URL #ref is rejected as source_ambiguous, and --path is reserved as git_subdir_unsupported. The fetch path clones with --filter=blob:none --no-checkout, checks out the requested ref (or the remote's HEAD symref by default), resolves HEAD to a commit, validates the manifest and entrypoint, refuses any symlinks in the artifact tree, then copies into an atomic install directory swap. Lock entries gain resolved_ref; the update probe runs git ls-remote and flips update.available when the upstream commit moved. Telemetry: the existing plugin.install span gains hyp_source_kind=git, git_url_host/owner/repo/ref/resolved_ref, content_hash, and manifest_hash. Child spans plugin.git.clone, plugin.git.checkout, plugin.git.resolve_ref, plugin.artifact.validate, and plugin.artifact.copy each carry status and error_kind. Git stderr is redacted for credentials before being surfaced. Tests cover URL parsing variants, the --ref/URL-fragment conflict, the subdir reservation, entrypoint traversal rejection, symlink detection, and content-hash stability. New hermetic smoke plugin_install_git_url builds a local bare repo and exercises the install end-to-end through the dispatcher. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat: boot integration for installed plugins (hy-jky3) (#11) bootKernel now reads plugin-lock.json, merges bundled and installed manifest pools, resolves dependencies across the merged set, and activates installed third-party plugins when the config names them. Rejects boot with `installed_shadows_bundled` when an installed plugin tries to shadow a bundled first-party name. Adds telemetry attributes (installed_available, installed_failed, installed_shadow_collisions, installed_selected) and a plugin.installed_active log per installed-and-selected plugin. Threads installed manifest metadata into the cross-plugin config validator via a new mergeInstalledManifestsIntoKnown helper, so third-party plugin sections are no longer flagged plugin_unknown and their provides/requires participate in sink-pair and capability-ambiguity checks. Updates hyp config validate, hyp init --from-file, and daemon status to feed the merged map in. Adds boot-installed unit tests covering merged pool, dep resolution over bundled+installed, shadow rejection, and config-validator behavior, plus a hermetic plugin_boot_installed smoke that installs a git-fixture plugin, activates it via config, runs its contributed command, and asserts the boot telemetry surface. * feat: update + trust UX for installed plugins (hy-qvmo) (#13) Add a confirmation gate to `hyp plugin install` and a real update flow to `hyp plugin update <plugin>` so remote installs no longer commit without the user (or `--yes`) seeing what is about to land. Install (git sources) - New `--yes`/`-y` flag. - Non-TTY without `--yes` rejects with `remote_install_confirmation_required` (exit code 2). - TTY without `--yes` prints a summary (source URL, resolved commit, plugin name + version, permissions, entrypoint, content_hash) and prompts `Proceed? [y/N]`. Both summary and prompt land on stderr so stdout stays parseable. - Local-dir installs keep their current non-interactive behavior — the confirmation gate only fires inside `fetchGitSource`. Update - `hyp plugin update <plugin>` now re-clones with the same source, runs manifest validate, and shows old vs. new resolved_ref/version/content_hash before the artifact swap. `--yes` skips the prompt; non-TTY without `--yes` rejects as above. On rejection the prior install is left intact because the rename swap only fires once `beforeCommit` returns `proceed=true`. - The bare `hyp plugin update` (no plugin name) keeps the legacy "refresh update_check state for every plugin" behavior so `outdated` can still be recomputed without committing to a re-install. Soft warnings (stderr only) - Manifest permissions containing `network` warn about broad scope. - Branch-shaped refs (and missing refs) warn that pinning a tag or commit SHA gives reproducible installs. Telemetry - `plugin.install` and a new `plugin.update` span both carry a `confirmation` attribute drawn from `confirmed`, `auto_yes`, `rejected`, `non_tty_no_yes`. The `plugin.installed` log row mirrors the attribute when it was set. - `fetch.FetchErrorKind` / `git_fetch.GitFetchErrorKind` gain `remote_install_confirmation_required` and `remote_install_rejected`. Tests + smoke - New `test/core/plugin-install-confirm.test.js` covers the pure helpers (`decideConfirmation`, `buildWarnings`, `sourceIsUnpinnedBranch`, `renderConfirmationSummary`) and exercises the `installPlugin` + `updatePlugin` integration against a hermetic file:// bare repo. - New env-gated acceptance smoke `hypaware-core/smoke/flows/plugin_install_github_url.js` installs a real GitHub plugin fixture at a pinned tag (opt-in via `HYP_SMOKE_REAL_GITHUB=1`, with overridable URL/ref/name env vars). Skips with a clear marker when the env var is unset so CI runs of `npm run smoke` do not hit the network. - The existing hermetic git-url and boot-installed smokes now pass `--yes` (they run with non-TTY buffer streams) and assert `confirmation=auto_yes` on the install span. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix: review findings on integration/github-install plugin install (hy-lpo3) (#18) Address all blocker and major findings from the dual-review on PR #6: confirm.js — switch to node:readline/promises so the awaited rl.question() actually returns a Promise and the interactive TTY prompt path can return a decision instead of throwing. update_check.js — pickLsRemoteSha now prefers the peeled `^{}` SHA when present so annotated tags compare against entry.resolved_ref correctly instead of producing spurious "update available" signals. Also wraps the ls-remote spawn with a hard timeout (default 5s, HYP_GIT_PROBE_TIMEOUT_MS-overridable, clamped) that emits a git_probe_timeout error_kind, and the post-install path now passes freshlyResolved=true so the probe is skipped entirely when we just resolved the upstream ref — the span still emits with probe_skipped=freshly_resolved for observability. git_source.js / resolver.js / install.js — strip user:pass@ userinfo from source.raw and source.gitUrl before they reach the lock entry, the confirmation prompt, or the install span. Persistence and display are always credential-free; clones rely on the user's git credential helper. Adds redactGitUrl / redactRawSource helpers. git_fetch.js / update_check.js — insert `--` end-of-options separator before user-controlled positionals in `git clone`, `git checkout`, and `git ls-remote` so a hostile URL or ref like `--upload-pack=<cmd>` cannot be parsed as a git option (CVE-2018-17456 family). Also reject leading-dash inputs in parseGitSource, applyGitSourceFlags, and the CLI parser as belt-and-braces defense before the spawn boundary. git_source.js — applyGitSourceFlags JSDoc no longer claims the subdir value is "still recorded on the returned spec" since the function throws unconditionally; the unreachable subdir spread is removed. Tests cover redactGitUrl/redactRawSource, leading-dash rejection across parser layers, peeled-tag SHA preference in pickLsRemoteSha, and the real readline/promises behavior of buildTtyPrompt via PassThrough streams. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: feature-launch <feature-launch@gas.city> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements the install pipeline for GitHub-URL plugins (hy-gh-1 / bead hy-2xeb).
New modules
src/core/plugin_install/git_source.jsandgit_fetch.jshandle git URL parsing and the clone / checkout / resolve / validate / copy pipeline, with per-stage spans (plugin.git.clone,plugin.git.checkout,plugin.git.resolve_ref,plugin.artifact.validate,plugin.artifact.copy). Lock entries now carryresolved_ref. CLI accepts--ref/--pathwithsource_ambiguousandgit_subdir_unsupportedguards.Test plan
npm test— 48/48 green (includes 20 new unit tests for git source resolver, entrypoint validation, symlink rejection, content hash stability)plugin_install_git_url(created in this PR) — greenplugin_install_local_dir— greenplugin.git.*andplugin.artifact.*spans for the smoke fixtureParent bead: hy-2xeb → integration/github-install (epic hy-dnk9)