feat: infrastructure packages and lint cleanup (#281)
* ci: consolidate duplicate workflows and merge CodeQL configs
Remove 17 duplicate workflow files that were split copies of the
combined originals. Each family (CI, CodeQL, Coverage, PR Build,
Alpha Release) had the same job duplicated across separate
push/pull_request/schedule/manual trigger files.
Merge codeql.yml and codescan.yml into a single codeql.yml with
a language matrix covering go, javascript-typescript, python,
and actions — matching the previous default setup coverage.
Remaining workflows (one per family):
- ci.yml (push + PR + manual)
- codeql.yml (push + PR + schedule, all languages)
- coverage.yml (push + PR + manual)
- alpha-release.yml (push + manual)
- pr-build.yml (PR + manual)
- release.yml (tag push)
- agent-verify.yml, auto-label.yml, auto-project.yml
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* feat: add collect, config, crypt, plugin packages and fix all lint issues
Add four new infrastructure packages with CLI commands:
- pkg/config: layered configuration (defaults → file → env → flags)
- pkg/crypt: crypto primitives (Argon2id, AES-GCM, ChaCha20, HMAC, checksums)
- pkg/plugin: plugin system with GitHub-based install/update/remove
- pkg/collect: collection subsystem (GitHub, BitcoinTalk, market, papers, excavate)
Fix all golangci-lint issues across the entire codebase (~100 errcheck,
staticcheck SA1012/SA1019/ST1005, unused, ineffassign fixes) so that
`core go qa` passes with 0 issues.
Closes #167, #168, #170, #250, #251, #252, #253, #254, #255, #256
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-04 11:34:43 +00:00
|
|
|
package plugin
|
|
|
|
|
|
|
|
|
|
import (
|
test: add coverage for lab, session, sigil, repos, plugin packages
Brings 5 packages from low/zero coverage to solid test suites:
- pkg/lab: 0% → 100% (Store pub/sub, Config env loading)
- pkg/session: 0% → 89.9% (transcript parser, HTML renderer, search, video)
- pkg/io/sigil: 43.8% → 98.5% (XOR/ShuffleMask obfuscators, ChaCha20-Poly1305)
- pkg/repos: 18.9% → 81.9% (registry, topo sort, directory scan, org detection)
- pkg/plugin: 54.8% → 67.1% (installer error paths, Remove, registry Load/Save)
Co-Authored-By: Virgil <virgil@lethean.io>
2026-02-24 13:29:15 +00:00
|
|
|
"context"
|
feat: infrastructure packages and lint cleanup (#281)
* ci: consolidate duplicate workflows and merge CodeQL configs
Remove 17 duplicate workflow files that were split copies of the
combined originals. Each family (CI, CodeQL, Coverage, PR Build,
Alpha Release) had the same job duplicated across separate
push/pull_request/schedule/manual trigger files.
Merge codeql.yml and codescan.yml into a single codeql.yml with
a language matrix covering go, javascript-typescript, python,
and actions — matching the previous default setup coverage.
Remaining workflows (one per family):
- ci.yml (push + PR + manual)
- codeql.yml (push + PR + schedule, all languages)
- coverage.yml (push + PR + manual)
- alpha-release.yml (push + manual)
- pr-build.yml (PR + manual)
- release.yml (tag push)
- agent-verify.yml, auto-label.yml, auto-project.yml
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* feat: add collect, config, crypt, plugin packages and fix all lint issues
Add four new infrastructure packages with CLI commands:
- pkg/config: layered configuration (defaults → file → env → flags)
- pkg/crypt: crypto primitives (Argon2id, AES-GCM, ChaCha20, HMAC, checksums)
- pkg/plugin: plugin system with GitHub-based install/update/remove
- pkg/collect: collection subsystem (GitHub, BitcoinTalk, market, papers, excavate)
Fix all golangci-lint issues across the entire codebase (~100 errcheck,
staticcheck SA1012/SA1019/ST1005, unused, ineffassign fixes) so that
`core go qa` passes with 0 issues.
Closes #167, #168, #170, #250, #251, #252, #253, #254, #255, #256
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-04 11:34:43 +00:00
|
|
|
"testing"
|
|
|
|
|
|
test: add coverage for lab, session, sigil, repos, plugin packages
Brings 5 packages from low/zero coverage to solid test suites:
- pkg/lab: 0% → 100% (Store pub/sub, Config env loading)
- pkg/session: 0% → 89.9% (transcript parser, HTML renderer, search, video)
- pkg/io/sigil: 43.8% → 98.5% (XOR/ShuffleMask obfuscators, ChaCha20-Poly1305)
- pkg/repos: 18.9% → 81.9% (registry, topo sort, directory scan, org detection)
- pkg/plugin: 54.8% → 67.1% (installer error paths, Remove, registry Load/Save)
Co-Authored-By: Virgil <virgil@lethean.io>
2026-02-24 13:29:15 +00:00
|
|
|
"forge.lthn.ai/core/go/pkg/io"
|
feat: infrastructure packages and lint cleanup (#281)
* ci: consolidate duplicate workflows and merge CodeQL configs
Remove 17 duplicate workflow files that were split copies of the
combined originals. Each family (CI, CodeQL, Coverage, PR Build,
Alpha Release) had the same job duplicated across separate
push/pull_request/schedule/manual trigger files.
Merge codeql.yml and codescan.yml into a single codeql.yml with
a language matrix covering go, javascript-typescript, python,
and actions — matching the previous default setup coverage.
Remaining workflows (one per family):
- ci.yml (push + PR + manual)
- codeql.yml (push + PR + schedule, all languages)
- coverage.yml (push + PR + manual)
- alpha-release.yml (push + manual)
- pr-build.yml (PR + manual)
- release.yml (tag push)
- agent-verify.yml, auto-label.yml, auto-project.yml
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* feat: add collect, config, crypt, plugin packages and fix all lint issues
Add four new infrastructure packages with CLI commands:
- pkg/config: layered configuration (defaults → file → env → flags)
- pkg/crypt: crypto primitives (Argon2id, AES-GCM, ChaCha20, HMAC, checksums)
- pkg/plugin: plugin system with GitHub-based install/update/remove
- pkg/collect: collection subsystem (GitHub, BitcoinTalk, market, papers, excavate)
Fix all golangci-lint issues across the entire codebase (~100 errcheck,
staticcheck SA1012/SA1019/ST1005, unused, ineffassign fixes) so that
`core go qa` passes with 0 issues.
Closes #167, #168, #170, #250, #251, #252, #253, #254, #255, #256
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-04 11:34:43 +00:00
|
|
|
"github.com/stretchr/testify/assert"
|
test: add coverage for lab, session, sigil, repos, plugin packages
Brings 5 packages from low/zero coverage to solid test suites:
- pkg/lab: 0% → 100% (Store pub/sub, Config env loading)
- pkg/session: 0% → 89.9% (transcript parser, HTML renderer, search, video)
- pkg/io/sigil: 43.8% → 98.5% (XOR/ShuffleMask obfuscators, ChaCha20-Poly1305)
- pkg/repos: 18.9% → 81.9% (registry, topo sort, directory scan, org detection)
- pkg/plugin: 54.8% → 67.1% (installer error paths, Remove, registry Load/Save)
Co-Authored-By: Virgil <virgil@lethean.io>
2026-02-24 13:29:15 +00:00
|
|
|
"github.com/stretchr/testify/require"
|
feat: infrastructure packages and lint cleanup (#281)
* ci: consolidate duplicate workflows and merge CodeQL configs
Remove 17 duplicate workflow files that were split copies of the
combined originals. Each family (CI, CodeQL, Coverage, PR Build,
Alpha Release) had the same job duplicated across separate
push/pull_request/schedule/manual trigger files.
Merge codeql.yml and codescan.yml into a single codeql.yml with
a language matrix covering go, javascript-typescript, python,
and actions — matching the previous default setup coverage.
Remaining workflows (one per family):
- ci.yml (push + PR + manual)
- codeql.yml (push + PR + schedule, all languages)
- coverage.yml (push + PR + manual)
- alpha-release.yml (push + manual)
- pr-build.yml (PR + manual)
- release.yml (tag push)
- agent-verify.yml, auto-label.yml, auto-project.yml
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* feat: add collect, config, crypt, plugin packages and fix all lint issues
Add four new infrastructure packages with CLI commands:
- pkg/config: layered configuration (defaults → file → env → flags)
- pkg/crypt: crypto primitives (Argon2id, AES-GCM, ChaCha20, HMAC, checksums)
- pkg/plugin: plugin system with GitHub-based install/update/remove
- pkg/collect: collection subsystem (GitHub, BitcoinTalk, market, papers, excavate)
Fix all golangci-lint issues across the entire codebase (~100 errcheck,
staticcheck SA1012/SA1019/ST1005, unused, ineffassign fixes) so that
`core go qa` passes with 0 issues.
Closes #167, #168, #170, #250, #251, #252, #253, #254, #255, #256
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-04 11:34:43 +00:00
|
|
|
)
|
|
|
|
|
|
test: add coverage for lab, session, sigil, repos, plugin packages
Brings 5 packages from low/zero coverage to solid test suites:
- pkg/lab: 0% → 100% (Store pub/sub, Config env loading)
- pkg/session: 0% → 89.9% (transcript parser, HTML renderer, search, video)
- pkg/io/sigil: 43.8% → 98.5% (XOR/ShuffleMask obfuscators, ChaCha20-Poly1305)
- pkg/repos: 18.9% → 81.9% (registry, topo sort, directory scan, org detection)
- pkg/plugin: 54.8% → 67.1% (installer error paths, Remove, registry Load/Save)
Co-Authored-By: Virgil <virgil@lethean.io>
2026-02-24 13:29:15 +00:00
|
|
|
// ── NewInstaller ───────────────────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
func TestNewInstaller_Good(t *testing.T) {
|
|
|
|
|
m := io.NewMockMedium()
|
|
|
|
|
reg := NewRegistry(m, "/plugins")
|
|
|
|
|
inst := NewInstaller(m, reg)
|
|
|
|
|
|
|
|
|
|
assert.NotNil(t, inst)
|
|
|
|
|
assert.Equal(t, m, inst.medium)
|
|
|
|
|
assert.Equal(t, reg, inst.registry)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ── Install error paths ────────────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
func TestInstall_Bad_InvalidSource(t *testing.T) {
|
|
|
|
|
m := io.NewMockMedium()
|
|
|
|
|
reg := NewRegistry(m, "/plugins")
|
|
|
|
|
inst := NewInstaller(m, reg)
|
|
|
|
|
|
|
|
|
|
err := inst.Install(context.Background(), "bad-source")
|
|
|
|
|
assert.Error(t, err)
|
|
|
|
|
assert.Contains(t, err.Error(), "invalid source")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestInstall_Bad_AlreadyInstalled(t *testing.T) {
|
|
|
|
|
m := io.NewMockMedium()
|
|
|
|
|
reg := NewRegistry(m, "/plugins")
|
|
|
|
|
_ = reg.Add(&PluginConfig{Name: "my-plugin", Version: "1.0.0"})
|
|
|
|
|
|
|
|
|
|
inst := NewInstaller(m, reg)
|
|
|
|
|
err := inst.Install(context.Background(), "org/my-plugin")
|
|
|
|
|
assert.Error(t, err)
|
|
|
|
|
assert.Contains(t, err.Error(), "already installed")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ── Remove ─────────────────────────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
func TestRemove_Good(t *testing.T) {
|
|
|
|
|
m := io.NewMockMedium()
|
|
|
|
|
reg := NewRegistry(m, "/plugins")
|
|
|
|
|
_ = reg.Add(&PluginConfig{Name: "removable", Version: "1.0.0"})
|
|
|
|
|
|
|
|
|
|
// Create plugin directory.
|
|
|
|
|
_ = m.EnsureDir("/plugins/removable")
|
|
|
|
|
_ = m.Write("/plugins/removable/plugin.json", `{"name":"removable"}`)
|
|
|
|
|
|
|
|
|
|
inst := NewInstaller(m, reg)
|
|
|
|
|
err := inst.Remove("removable")
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
|
|
// Plugin removed from registry.
|
|
|
|
|
_, ok := reg.Get("removable")
|
|
|
|
|
assert.False(t, ok)
|
|
|
|
|
|
|
|
|
|
// Directory cleaned up.
|
|
|
|
|
assert.False(t, m.Exists("/plugins/removable"))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestRemove_Good_DirAlreadyGone(t *testing.T) {
|
|
|
|
|
m := io.NewMockMedium()
|
|
|
|
|
reg := NewRegistry(m, "/plugins")
|
|
|
|
|
_ = reg.Add(&PluginConfig{Name: "ghost", Version: "1.0.0"})
|
|
|
|
|
// No directory exists — should still succeed.
|
|
|
|
|
|
|
|
|
|
inst := NewInstaller(m, reg)
|
|
|
|
|
err := inst.Remove("ghost")
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
|
|
_, ok := reg.Get("ghost")
|
|
|
|
|
assert.False(t, ok)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestRemove_Bad_NotFound(t *testing.T) {
|
|
|
|
|
m := io.NewMockMedium()
|
|
|
|
|
reg := NewRegistry(m, "/plugins")
|
|
|
|
|
inst := NewInstaller(m, reg)
|
|
|
|
|
|
|
|
|
|
err := inst.Remove("nonexistent")
|
|
|
|
|
assert.Error(t, err)
|
|
|
|
|
assert.Contains(t, err.Error(), "plugin not found")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ── Update error paths ─────────────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
func TestUpdate_Bad_NotFound(t *testing.T) {
|
|
|
|
|
m := io.NewMockMedium()
|
|
|
|
|
reg := NewRegistry(m, "/plugins")
|
|
|
|
|
inst := NewInstaller(m, reg)
|
|
|
|
|
|
|
|
|
|
err := inst.Update(context.Background(), "missing")
|
|
|
|
|
assert.Error(t, err)
|
|
|
|
|
assert.Contains(t, err.Error(), "plugin not found")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ── ParseSource ────────────────────────────────────────────────────
|
|
|
|
|
|
feat: infrastructure packages and lint cleanup (#281)
* ci: consolidate duplicate workflows and merge CodeQL configs
Remove 17 duplicate workflow files that were split copies of the
combined originals. Each family (CI, CodeQL, Coverage, PR Build,
Alpha Release) had the same job duplicated across separate
push/pull_request/schedule/manual trigger files.
Merge codeql.yml and codescan.yml into a single codeql.yml with
a language matrix covering go, javascript-typescript, python,
and actions — matching the previous default setup coverage.
Remaining workflows (one per family):
- ci.yml (push + PR + manual)
- codeql.yml (push + PR + schedule, all languages)
- coverage.yml (push + PR + manual)
- alpha-release.yml (push + manual)
- pr-build.yml (PR + manual)
- release.yml (tag push)
- agent-verify.yml, auto-label.yml, auto-project.yml
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* feat: add collect, config, crypt, plugin packages and fix all lint issues
Add four new infrastructure packages with CLI commands:
- pkg/config: layered configuration (defaults → file → env → flags)
- pkg/crypt: crypto primitives (Argon2id, AES-GCM, ChaCha20, HMAC, checksums)
- pkg/plugin: plugin system with GitHub-based install/update/remove
- pkg/collect: collection subsystem (GitHub, BitcoinTalk, market, papers, excavate)
Fix all golangci-lint issues across the entire codebase (~100 errcheck,
staticcheck SA1012/SA1019/ST1005, unused, ineffassign fixes) so that
`core go qa` passes with 0 issues.
Closes #167, #168, #170, #250, #251, #252, #253, #254, #255, #256
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-04 11:34:43 +00:00
|
|
|
func TestParseSource_Good_OrgRepo(t *testing.T) {
|
|
|
|
|
org, repo, version, err := ParseSource("host-uk/core-plugin")
|
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
assert.Equal(t, "host-uk", org)
|
|
|
|
|
assert.Equal(t, "core-plugin", repo)
|
|
|
|
|
assert.Equal(t, "", version)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestParseSource_Good_OrgRepoVersion(t *testing.T) {
|
|
|
|
|
org, repo, version, err := ParseSource("host-uk/core-plugin@v1.0.0")
|
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
assert.Equal(t, "host-uk", org)
|
|
|
|
|
assert.Equal(t, "core-plugin", repo)
|
|
|
|
|
assert.Equal(t, "v1.0.0", version)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestParseSource_Good_VersionWithoutPrefix(t *testing.T) {
|
|
|
|
|
org, repo, version, err := ParseSource("org/repo@1.2.3")
|
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
assert.Equal(t, "org", org)
|
|
|
|
|
assert.Equal(t, "repo", repo)
|
|
|
|
|
assert.Equal(t, "1.2.3", version)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestParseSource_Bad_Empty(t *testing.T) {
|
|
|
|
|
_, _, _, err := ParseSource("")
|
|
|
|
|
assert.Error(t, err)
|
|
|
|
|
assert.Contains(t, err.Error(), "source is empty")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestParseSource_Bad_NoSlash(t *testing.T) {
|
|
|
|
|
_, _, _, err := ParseSource("just-a-name")
|
|
|
|
|
assert.Error(t, err)
|
|
|
|
|
assert.Contains(t, err.Error(), "org/repo")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestParseSource_Bad_TooManySlashes(t *testing.T) {
|
|
|
|
|
_, _, _, err := ParseSource("a/b/c")
|
|
|
|
|
assert.Error(t, err)
|
|
|
|
|
assert.Contains(t, err.Error(), "org/repo")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestParseSource_Bad_EmptyOrg(t *testing.T) {
|
|
|
|
|
_, _, _, err := ParseSource("/repo")
|
|
|
|
|
assert.Error(t, err)
|
|
|
|
|
assert.Contains(t, err.Error(), "org/repo")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestParseSource_Bad_EmptyRepo(t *testing.T) {
|
|
|
|
|
_, _, _, err := ParseSource("org/")
|
|
|
|
|
assert.Error(t, err)
|
|
|
|
|
assert.Contains(t, err.Error(), "org/repo")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestParseSource_Bad_EmptyVersion(t *testing.T) {
|
|
|
|
|
_, _, _, err := ParseSource("org/repo@")
|
|
|
|
|
assert.Error(t, err)
|
|
|
|
|
assert.Contains(t, err.Error(), "version is empty")
|
|
|
|
|
}
|