Skip to content

feat(packs): remote packs and app level default_tags#27

Merged
faloker merged 6 commits into
mainfrom
feat/pack-install-change
Jul 6, 2026
Merged

feat(packs): remote packs and app level default_tags#27
faloker merged 6 commits into
mainfrom
feat/pack-install-change

Conversation

@faloker

@faloker faloker commented Jul 6, 2026

Copy link
Copy Markdown
Collaborator

Summary

Reworks pack installation to be an eager, manifest-driven operation for all pack types, adds GitHub Releases-based remote pack resolution, and introduces org-wide default_tags in app config that are merged beneath each pack's own default_tags.

Manifest-derived pack install

  • Install is now eager for all pack types: download/upload goes to a staging dir, the pack's manifest command derives its name and version, then the pack is relocated and upserted. The overloaded name field is removed from the install flow.
  • Failures (bad repo, no matching asset, checksum mismatch, manifest error, missing local path) surface at install time and leave no DB row behind.
  • Runtime resolution is unchanged — the cached binary is found by scanning the version dir, so the install-time cache is a hit.

Remote pack resolution via GitHub Releases

  • Empty version resolves the latest release; otherwise the tag is looked up as both v<version> and <version>, so the v prefix convention is handled transparently. The resolved tag is pinned.
  • The platform asset is selected by matching *_<os>_<arch>.tar.gz and checksum-verified; the in-tarball binary name is derived from the asset prefix, falling back to the single executable in the archive.

Org-wide default_tags

  • New default_tags app-config setting (migration 018), merged beneath each pack's own default_tags when parameters are loaded from the DB — pack-level keys win.
  • Server-side validation, plus read-only inheritance display in the pack parameters dialog.

Frontend

  • Install dialog: name input dropped; remote install is source + optional version, upload is a file picker. Install errors surface as a toast while the dialog stays open.
  • Remote pack sources render as an org/repo slug linked to the repo (tooltip carries the full source); uploaded/local sources are tooltip-backed instead of clipping silently.

Tests & specs

  • Resolver and install-handler tests: latest/pinned/prefix resolution, asset matching, checksum mismatch, not-found, binary-name fallback, manifest-derived identity, no-row-on-failure.
  • Tests for default_tags merge in scenario runs, config API, and detonator env.
  • Archives the manifest-derived-pack-install and org-default-tags OpenSpec changes; adds the settings-page-redesign proposal.

faloker added 4 commits July 1, 2026 14:42
Install is now an eager operation for all pack types. The overloaded
`name` field is removed from the install flow; a pack's identity comes
from its own manifest instead.

- Remote resolution goes through the GitHub Releases API: empty version
  resolves the latest release, otherwise the tag is looked up trying both
  `v<version>` and `<version>` so the `v` prefix and tag convention are
  handled transparently. The platform asset is selected by matching
  `*_<os>_<arch>.tar.gz`, checksum-verified, and the resolved tag is pinned.
- The in-tarball binary name is derived from the asset prefix, falling
  back to the single executable in the archive.
- Install downloads/writes to a staging dir, runs the pack `manifest`
  command to derive name+version, then relocates and upserts. Failures
  (bad repo, no asset, checksum mismatch, manifest error, missing local
  path) surface at install time with no DB row created.
- Runtime resolution is unchanged: the cached binary is located by
  scanning the version dir, so the install-time cache is a hit.
- Frontend: drop the name input, remote = source + optional version,
  upload = file picker; surface install errors as a toast so they are
  visible while the dialog stays open.

Adds resolver and install-handler tests covering latest/pinned/prefix
resolution, asset matching, checksum mismatch, not-found, binary-name
fallback, manifest-derived identity, and no-row-on-failure.
Remote packs stored their source as github.com/org/repo and rendered it
truncated, clipping long slugs with no recovery. Display the org/repo
slug (host dropped) as a link to the repo with a hover external-link
affordance and a tooltip carrying the full source; keep uploaded/local
sources tooltip-backed so they no longer clip silently.
Org-wide default_tags in app config are now merged beneath each pack's
own default_tags (pack-level keys win) when parameters are loaded from
the DB, with server-side validation and read-only inheritance display
in the pack parameters dialog. Also archives the completed
manifest-derived-pack-install change and adds the settings-page-redesign
proposal that depends on this one.
Copilot AI review requested due to automatic review settings July 6, 2026 19:02

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the pack install lifecycle to be manifest-driven (name/version derived from the pack binary rather than operator input), adds GitHub Releases API–based remote resolution (including “latest” when version is omitted), and introduces org-wide default_tags stored in app settings and merged into pack execution while being displayed read-only in the pack parameters UI.

Changes:

  • Remove operator-supplied pack name from install/upload flows; derive identity from manifest and make install eager (download/validate at install time).
  • Resolve remote packs via GitHub Releases API (tag-based or latest), selecting platform assets and verifying checksums.
  • Add app-level default_tags, merge them under pack-level tags for execution, and display inherited tags in the pack parameters editor.

Reviewed changes

Copilot reviewed 43 out of 44 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
web/frontend/src/routes/packs/+page.svelte Removes pack-name input; updates install/upload UX and uses toasts for install feedback.
web/frontend/src/lib/components/SchemaForm.svelte Adds read-only display of inherited org default tags inside default_tags.
web/frontend/src/lib/components/PackParametersDialog.svelte Fetches app config to supply inherited default_tags to the schema form.
web/frontend/src/lib/components/PackCard.svelte Improves remote pack source display by linking to GitHub repo slug when applicable.
web/frontend/src/lib/api/client.ts Updates upload API to no longer send a name field.
web/frontend/package-lock.json Bumps js-yaml dependency metadata.
openspec/specs/packs/spec.md Updates pack install requirements to reflect manifest-derived identity and GitHub Releases resolution.
openspec/specs/pack-execution/spec.md Specifies org default_tags merge precedence beneath pack-level tags.
openspec/specs/app-settings/spec.md Adds specification for app-level default_tags storage/validation and UI inheritance display.
openspec/changes/settings-page-redesign/tasks.md Adds tasks for upcoming settings page redesign and shared KV editor extraction.
openspec/changes/settings-page-redesign/specs/settings-page/spec.md Adds requirements for tabbed settings layout and shared string-map editor.
openspec/changes/settings-page-redesign/proposal.md Documents motivation and scope of the settings page redesign.
openspec/changes/settings-page-redesign/design.md Design decisions for the settings page redesign and shared editor extraction.
openspec/changes/settings-page-redesign/.openspec.yaml Declares spec-driven change metadata for settings redesign.
openspec/changes/archive/2026-07-06-org-default-tags/tasks.md Archives tasks for org-wide default tags implementation.
openspec/changes/archive/2026-07-06-org-default-tags/specs/pack-execution/spec.md Archives pack-execution delta for org default tags.
openspec/changes/archive/2026-07-06-org-default-tags/specs/app-settings/spec.md Archives app-settings delta for org default tags.
openspec/changes/archive/2026-07-06-org-default-tags/proposal.md Archives org default tags proposal.
openspec/changes/archive/2026-07-06-org-default-tags/design.md Archives org default tags design.
openspec/changes/archive/2026-07-06-org-default-tags/.openspec.yaml Archives org default tags change metadata.
openspec/changes/archive/2026-07-01-manifest-derived-pack-install/tasks.md Archives tasks for manifest-derived install lifecycle.
openspec/changes/archive/2026-07-01-manifest-derived-pack-install/specs/packs/spec.md Archives packs spec delta for manifest-derived installs.
openspec/changes/archive/2026-07-01-manifest-derived-pack-install/proposal.md Archives manifest-derived install proposal.
openspec/changes/archive/2026-07-01-manifest-derived-pack-install/design.md Archives manifest-derived install design.
openspec/changes/archive/2026-07-01-manifest-derived-pack-install/.openspec.yaml Archives manifest-derived install change metadata.
internal/web/types.go Marks install request name as optional/ignored for backward compatibility.
internal/web/scenarios.go Merges org default tags beneath pack default_tags when building pack configs from DB.
internal/web/scenarios_test.go Adds tests for org tag merge semantics and non-mutation guarantees.
internal/web/packs_handler.go Reworks install/upload handlers to eagerly validate binaries and derive identity from manifest.
internal/web/handlers.go Adds default_tags validation branch to config update handler.
internal/web/api_packs_test.go Updates pack install/list test to match eager local install and manifest-derived name.
internal/web/api_packs_install_test.go Adds install handler tests for remote/latest, manifest name derivation, and failure cases.
internal/web/api_config_test.go Adds tests ensuring default_tags validation rejects invalid shapes and persists valid maps.
internal/testutil/fakes/fakes.go Extends fake config store to round-trip default_tags.
internal/packs/resolver/resolver.go Adds GitHub Releases API resolution, asset selection, checksum verification, and extraction logic.
internal/packs/resolver/resolver_test.go Adds resolver tests for latest/tag resolution, asset selection edge cases, and extraction fallbacks.
internal/packs/resolver/resolver_concurrency_test.go Updates concurrency test to use API base URL and JSON release responses.
internal/detonators/simrun_detonator_test.go Ensures map[string]string tag maps still JSON-encode correctly for TF_VAR env.
internal/db/migrations/018_default_tags_appconfig.up.sql Backfills default_tags key in app_config.
internal/db/migrations/018_default_tags_appconfig.down.sql Removes default_tags key on rollback.
internal/db/config.go Maps default_tags in typed app config parsing/serialization.
internal/db/config_test.go Adds coverage for parsing/marshaling default_tags in app config.
internal/config/appconfig.go Adds DefaultTags field and default value to AppConfig.
internal/config/appconfig_test.go Updates default app config test for new DefaultTags field.
Files not reviewed (1)
  • web/frontend/package-lock.json: Generated file

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread internal/packs/resolver/resolver.go Outdated
Comment on lines 120 to 126
// validatePackConfig validates the pack configuration.
func (r *Resolver) validatePackConfig(cfg PackConfig) error {
if cfg.Source == "" {
return fmt.Errorf("pack %s: source is required", cfg.Name)
}
if cfg.Version == "" {
return fmt.Errorf("pack %s: version is required for remote packs", cfg.Name)
}
return nil
}
Comment on lines +75 to +83
var pack *db.Pack
if config.PackType(req.Type) == config.PackTypeRemote {
pack, err = h.installRemote(r.Context(), res, req)
} else {
pack, err = h.installLocal(r.Context(), res, req)
}
if err != nil {
writeError(w, http.StatusBadRequest, err.Error())
return
Comment on lines +358 to 365
// HandleUploadPack handles POST /api/packs/upload.
//
// The uploaded binary is written to a staging location, its manifest command is
// run to derive the pack's identity, then it is relocated to
// <DataDir>/packs/<name>/upload/<name>. The request's `name` form field is
// ignored. A manifest failure aborts the install with no DB record.
func (h *PackHandlers) HandleUploadPack(w http.ResponseWriter, r *http.Request) {
r.Body = http.MaxBytesReader(w, r.Body, maxUploadSize)
@github-actions github-actions Bot added the size/XXL PR size: XXL label Jul 6, 2026
@faloker faloker merged commit 5fc1708 into main Jul 6, 2026
2 of 3 checks passed
@faloker faloker deleted the feat/pack-install-change branch July 6, 2026 19:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/XXL PR size: XXL

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants