Compare commits

...

7 Commits

Author SHA1 Message Date
788988195f Merge pull request '[migrate] vanity import go.moleculesai.app/plugin/gh-identity (internal#71 smoke)' (#3) from migrate/issue-71-vanity-imports into main
All checks were successful
CI / Shellcheck + wrapper tests (push) Successful in 29s
CI / Go build + test + vet (push) Successful in 50s
2026-05-09 01:04:45 +00:00
claude-ceo-assistant
d8403251d2 lint: extend gate to .json files (internal#71 — package metadata drift)
All checks were successful
CI / Shellcheck + wrapper tests (pull_request) Successful in 47s
CI / Go build + test + vet (pull_request) Successful in 3m17s
2026-05-07 22:57:14 +00:00
claude-ceo-assistant
b2ed330475 fix(post-suspension): vanity import path go.moleculesai.app/plugin/gh-identity (closes molecule-ai/internal#71 phase 2)
All checks were successful
CI / Shellcheck + wrapper tests (pull_request) Successful in 24s
CI / Go build + test + vet (pull_request) Successful in 1m10s
Migrates go.mod + the single Go import + a stale go.mod replace-comment
+ README require example off the dead github.com/Molecule-AI/ identity
and onto the vanity host go.moleculesai.app, owned by us. Adds a
structural lint test that walks every *.go / *.mod / Dockerfile / *.md
and rejects future re-introduction of either the literal
github.com/Molecule-AI/ string or the historical
Molecule-AI/molecule-monorepo path.

Why a vanity host and not git.moleculesai.app/molecule-ai/...:
the latter just relocates the lock-in. 2026-05-06 didn't teach us
'Gitea > GitHub'; it taught us 'vendor URLs in source code are a future
incident'. With go.moleculesai.app, the next SCM migration edits one
config (the responder) instead of every import statement. See
internal#71 for the full rationale + the alternatives rejected.

Smoke-validation for this migration sweep — chosen as the first PR
because it has the smallest blast radius (1 import line).
Following PRs: molecule-cli, molecule-controlplane, molecule-core
(parallel after this lands).

Test plan:
- go build ./... — clean
- go test ./... — internal/ghidentity green
- TestNoLegacyGitHubImportPaths — passes on clean tree, FAILS on
  injected canary string (mutation-tested before commit)

Open dependency: go.moleculesai.app responder must be deployed before
external 'go install go.moleculesai.app/plugin/gh-identity@latest'
works. Internal builds are unaffected (self-referential module path,
no external fetch needed). Responder code prepared in worker.js;
deploy tracked separately.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 22:23:51 +00:00
bfc64dd95a Merge pull request 'fix(post-suspension): migrate github.com/Molecule-AI refs to git.moleculesai.app (Class G #168)' (#2) from fix/post-suspension-github-urls into main
All checks were successful
CI / Shellcheck + wrapper tests (push) Successful in 33s
CI / Go build + test + vet (push) Successful in 1m57s
2026-05-07 20:04:21 +00:00
cfd7c6d647 fix(post-suspension): migrate github.com/Molecule-AI refs to git.moleculesai.app (Class G #168)
All checks were successful
CI / Shellcheck + wrapper tests (pull_request) Successful in 29s
CI / Go build + test + vet (pull_request) Successful in 1m32s
The GitHub org Molecule-AI was suspended on 2026-05-06; canonical SCM
is now Gitea at https://git.moleculesai.app/molecule-ai/. Stale
github.com/Molecule-AI/... URLs return 404 and break tooling that
clones / pip-installs / curls them.

This bundles all non-Go-module URL fixes for this repo into a single PR.
Go module path references (in *.go, go.mod, go.sum) are out of scope
here -- tracked separately under Task #140.

Token-auth clone URLs also flip ${GITHUB_TOKEN} -> ${GITEA_TOKEN} since
the GitHub token does not auth against Gitea.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 13:03:41 -07:00
security-auditor
ba4da59f77 ci: re-trigger after runner-config v2 (CONFIG_FILE fix)
All checks were successful
CI / Shellcheck + wrapper tests (push) Successful in 1m56s
CI / Go build + test + vet (push) Successful in 10m10s
Verify whether failure was setup-python toolcache class (now fixed via
orchestrator's runners-1-8 recreate) or real CODE class.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 02:57:26 -07:00
81602fcac9 Merge pull request 'docs(install): migrate plugin-architecture-v2 link to git.moleculesai.app (#37)' (#1) from fix/install-path-gitea into main
All checks were successful
CI / Shellcheck + wrapper tests (push) Successful in 23s
CI / Go build + test + vet (push) Successful in 10m1s
2026-05-07 09:24:06 +00:00
5 changed files with 152 additions and 6 deletions

View File

@ -75,7 +75,7 @@ manifest rename:
Monorepo side:
```
manifest.json:plugins += {name: "gh-identity", repo: "Molecule-AI/molecule-ai-plugin-gh-identity", ref: "main"}
workspace-server/go.mod: require github.com/Molecule-AI/molecule-ai-plugin-gh-identity
workspace-server/go.mod: require go.moleculesai.app/plugin/gh-identity
workspace-server/cmd/server/main.go: pluginloader.BuildRegistry()
```
@ -115,5 +115,5 @@ shared and platform-managed, not in plugin scope).
- internal `product/plugin-architecture-v2.md` — target arch for v2
migration
[molecule-core#1957]: https://github.com/Molecule-AI/molecule-core/issues/1957
[molecule-core#1957]: https://git.moleculesai.app/molecule-ai/molecule-core/issues/1957
[plugin-architecture-v2]: https://git.moleculesai.app/molecule-ai/internal/src/branch/main/product/plugin-architecture-v2.md

4
go.mod
View File

@ -1,4 +1,4 @@
module github.com/Molecule-AI/molecule-ai-plugin-gh-identity
module go.moleculesai.app/plugin/gh-identity
go 1.25.0
@ -9,7 +9,7 @@ require gopkg.in/yaml.v3 v3.0.1
// is needed. If we ever need to reference exported types from
// molecule-monorepo/platform, uncomment:
//
// replace github.com/Molecule-AI/molecule-monorepo/platform => ../molecule-monorepo/workspace-server
// replace go.moleculesai.app/core/platform => ../molecule-core/workspace-server
//
// Keeping this out of the require list lets the plugin build standalone in CI
// without checking out the monorepo.

View File

@ -32,7 +32,7 @@ axis. At that point:
- Grade-A hot reload becomes possible (platform can re-emit the file
without a workspace restart).
[v2]: https://github.com/Molecule-AI/internal/blob/main/product/plugin-architecture-v2.md
[v2]: https://git.moleculesai.app/molecule-ai/internal/blob/main/product/plugin-architecture-v2.md
---

View File

@ -0,0 +1,146 @@
// Issue molecule-ai/internal#71 lint gate.
//
// Walks every *.go file in the module + the go.mod declaration + any
// Dockerfile in the repo, and rejects any reference to the dead
// github.com/Molecule-AI/* identity (or the historical
// Molecule-AI/molecule-monorepo path).
//
// We had a 374+131+30+1-line "github.com/Molecule-AI/" footprint across
// the org pre-migration. The class of bug this gate prevents:
//
// - copy-pastes from old branches re-introducing the dead path
// - Dockerfile -ldflags strings drifting back to github.com on a
// refactor (the path has to match the module declaration to inject
// buildinfo correctly; if they disagree the binary builds but
// reports a wrong / stale GitSHA)
// - new modules added to the repo with the wrong import root because
// someone copied an old go.mod without thinking
//
// Why not just a CI shell grep: a Go test runs everywhere `go test ./...`
// runs, including local pre-push hooks and contributor IDEs. The gate
// fires immediately, with a per-file message that points at the line —
// CI shell grep failures are silent until the runner picks them up.
package pluginloader
import (
"os"
"path/filepath"
"strings"
"testing"
)
// forbiddenSubstrings is the literal-match list. Each string MUST NOT
// appear anywhere under the module root. Entries are checked with
// substring matching, not regex — keep the patterns specific enough
// that a false-positive needs an explicit allowlist entry.
var forbiddenSubstrings = []string{
"github.com/Molecule-AI/",
"Molecule-AI/molecule-monorepo",
}
// allowlistedFiles is the per-file escape hatch. Empty by default —
// add an entry only when there is a documented reason a forbidden
// string MUST appear (e.g. a regression-test fixture that asserts
// the lint gate itself rejects the string). Each entry MUST be
// accompanied by a comment explaining why.
var allowlistedFiles = map[string]bool{
// (intentionally empty — add only with justification)
}
func TestNoLegacyGitHubImportPaths(t *testing.T) {
moduleRoot, err := findModuleRoot()
if err != nil {
t.Fatalf("findModuleRoot: %v", err)
}
checkExt := map[string]bool{
".go": true,
".mod": true,
".sum": false, // go.sum is auto-generated, refs flow from go.mod
".sh": true,
".yml": true,
".yaml": true,
".toml": true,
".md": true,
".json": true, // package.json / tsconfig.json — catches ref drift in package metadata
}
checkBasename := map[string]bool{
"Dockerfile": true,
"Dockerfile.tenant": true,
}
violations := 0
walkErr := filepath.Walk(moduleRoot, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if info.IsDir() {
// Skip vendor + .git + node_modules — not our code.
base := info.Name()
if base == "vendor" || base == ".git" || base == "node_modules" || base == "testdata" {
return filepath.SkipDir
}
return nil
}
ext := filepath.Ext(path)
base := filepath.Base(path)
if !checkExt[ext] && !checkBasename[base] {
return nil
}
rel, _ := filepath.Rel(moduleRoot, path)
if allowlistedFiles[rel] {
return nil
}
// Skip the lint test itself — it legitimately names the forbidden
// strings as match patterns.
if strings.HasSuffix(rel, "import_path_lint_test.go") {
return nil
}
data, err := os.ReadFile(path)
if err != nil {
return err
}
text := string(data)
for _, bad := range forbiddenSubstrings {
if strings.Contains(text, bad) {
// Find the line number for a useful error message.
for lineNo, line := range strings.Split(text, "\n") {
if strings.Contains(line, bad) {
t.Errorf("%s:%d — forbidden substring %q (use go.moleculesai.app/<area>/... per molecule-ai/internal#71)", rel, lineNo+1, bad)
violations++
break
}
}
}
}
return nil
})
if walkErr != nil {
t.Fatalf("walk: %v", walkErr)
}
if violations > 0 {
t.Logf("Total violations: %d. Add to allowlistedFiles ONLY with a documented justification.", violations)
}
}
// findModuleRoot walks up from the test's CWD to find go.mod. The Go
// test harness sets CWD to the package directory; the module root may
// be one or more parents up.
func findModuleRoot() (string, error) {
cwd, err := os.Getwd()
if err != nil {
return "", err
}
dir := cwd
for {
if _, err := os.Stat(filepath.Join(dir, "go.mod")); err == nil {
return dir, nil
}
parent := filepath.Dir(dir)
if parent == dir {
return "", os.ErrNotExist
}
dir = parent
}
}

View File

@ -19,7 +19,7 @@ import (
"fmt"
"os"
"github.com/Molecule-AI/molecule-ai-plugin-gh-identity/internal/ghidentity"
"go.moleculesai.app/plugin/gh-identity/internal/ghidentity"
)
// Result bundles what BuildRegistry returns — a single mutator plus