refactor: complete check 2c retarget from block/core to block/pluginsdk

Standalone plugins now build against git.dev.alexdunmow.com/block/pluginsdk.
Check 2c requires a pluginsdk module require (rule missing-pluginsdk-require)
and enforces its version against the CMS anchor (rule pluginsdk-version-mismatch)
once the CMS migrates; a coexisting block/core require stays allowed
(calcomblock keeps core for captcha).

- check_sdkboundaries.go: degrade the 2c OK message gracefully when the
  pluginsdk version anchor is empty (transition period) — omit the version
  clause instead of printing "SDK version ".
- check_rbac.go: document pluginsdk in the definitions-only module comment.
- plugin_sdk_versions_test.go: retarget fixtures to pluginsdk; add cases for
  missing-pluginsdk-require, pluginsdk-version-mismatch, a forbidden core
  replace directive, and an allowed coexisting core require.
- lint_test.go: synthesized plugin repos now require pluginsdk (replace-
  directive case replaces pluginsdk).
- registry_test.go: add checks 30 and 31 to the canonical order (were added
  to the registry without updating this test).
- golden: regenerate — check count 32 -> 34 (checks 30/31 SKIP in fixtures).
- README.md: describe 2c as the pluginsdk boundary.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Alex Dunmow 2026-07-07 11:13:42 +08:00
parent de43bca80f
commit ff4de855cc
10 changed files with 94 additions and 25 deletions

View File

@ -96,7 +96,7 @@ tool prints in each check header):
| 1 | Secret env var reads | Secret env vars (`JWT_SECRET`, `VAULT_*`, encryption keys, …) are read only inside `config.Load()` (`config/config.go`) or `_test.go` files. | | 1 | Secret env var reads | Secret env vars (`JWT_SECRET`, `VAULT_*`, encryption keys, …) are read only inside `config.Load()` (`config/config.go`) or `_test.go` files. |
| 2 | RBAC registration | Every RPC method is registered in the RBAC interceptor. Internal / plugin-managed services (e.g. `ManagementService`, Symposium's `WikiService`) are exempted. | | 2 | RBAC registration | Every RPC method is registered in the RBAC interceptor. Internal / plugin-managed services (e.g. `ManagementService`, Symposium's `WikiService`) are exempted. |
| 2b | Plugin proto ownership | Plugins own their proto/RBAC definitions correctly (no poaching of core proto packages). | | 2b | Plugin proto ownership | Plugins own their proto/RBAC definitions correctly (no poaching of core proto packages). |
| 2c | Plugin SDK boundaries | Standalone plugins import only the published `block/core` SDK boundary — verified via imports, `go.mod`, and version. | | 2c | Plugin SDK boundaries | Standalone plugins build against the published `block/pluginsdk` SDK (a coexisting `block/core` require is allowed) — verified via imports, `go.mod`, and version. |
| 2d | sqlc UUID overrides | sqlc UUID overrides in standalone plugins and `cmd` configs must use `github.com/google/uuid`. | | 2d | sqlc UUID overrides | sqlc UUID overrides in standalone plugins and `cmd` configs must use `github.com/google/uuid`. |
| 2e | `any` usage | Warns on `any` usage in Go and TypeScript (capped at 120 printed warnings). | | 2e | `any` usage | Warns on `any` usage in Go and TypeScript (capped at 120 printed warnings). |
| 2f | Codegen freshness | `sqlc compile` and `buf generate` must succeed for every scanned root that defines them (generated code is up to date). | | 2f | Codegen freshness | `sqlc compile` and `buf generate` must succeed for every scanned root that defines them (generated code is up to date). |

View File

@ -23,11 +23,14 @@ const coreSDKModulePath = "git.dev.alexdunmow.com/block/core"
// "missing from MethodRoles", a not-applicable result rather than a finding. // "missing from MethodRoles", a not-applicable result rather than a finding.
// //
// - core: the shared proto SDK. // - core: the shared proto SDK.
// - pluginsdk: the standalone-plugin SDK (2026-07-07 extraction). It
// carries proto definitions but serves nothing.
// - cli: the ninja developer CLI (WO-WZ-023). It vendors // - cli: the ninja developer CLI (WO-WZ-023). It vendors
// orchestrator/v1/plugin_registry.proto to generate a CLIENT for the // orchestrator/v1/plugin_registry.proto to generate a CLIENT for the
// registry; it has no server and no RBAC interceptor. // registry; it has no server and no RBAC interceptor.
var definitionsOnlyModulePaths = map[string]bool{ var definitionsOnlyModulePaths = map[string]bool{
coreSDKModulePath: true, coreSDKModulePath: true,
"git.dev.alexdunmow.com/block/pluginsdk": true,
"git.dev.alexdunmow.com/block/cli": true, "git.dev.alexdunmow.com/block/cli": true,
} }

View File

@ -11,7 +11,9 @@ func init() {
var pluginGoModViolations []pluginGoModViolation var pluginGoModViolations []pluginGoModViolation
var standalonePluginLabels []string var standalonePluginLabels []string
checkedStandalonePluginRoots := make(map[string]bool) checkedStandalonePluginRoots := make(map[string]bool)
requiredSDKVersion, requiredSDKVersionErr := currentCMSCoreSDKVersion() // Version anchor = the CMS backend's pluginsdk pin; empty (skip
// version enforcement) until the CMS itself migrates to pluginsdk.
requiredSDKVersion, requiredSDKVersionErr := currentCMSPluginSDKVersion()
if requiredSDKVersionErr != nil { if requiredSDKVersionErr != nil {
rep.Fatal("failed to resolve CMS SDK version: %v", requiredSDKVersionErr) rep.Fatal("failed to resolve CMS SDK version: %v", requiredSDKVersionErr)
} }
@ -72,7 +74,11 @@ func init() {
} }
} }
} else if len(standalonePluginLabels) > 0 { } else if len(standalonePluginLabels) > 0 {
if requiredSDKVersion != "" {
rep.OK("Standalone plugin imports and go.mod stay on SDK version %s", requiredSDKVersion) rep.OK("Standalone plugin imports and go.mod stay on SDK version %s", requiredSDKVersion)
} else {
rep.OK("Standalone plugin imports and go.mod build against the plugin SDK")
}
} else if ctx.includeCoreTargets { } else if ctx.includeCoreTargets {
rep.OK("%s/go.mod does not locally replace %s", ctx.backendTargets[0].displayOrRoot(), blockCoreImportPrefix) rep.OK("%s/go.mod does not locally replace %s", ctx.backendTargets[0].displayOrRoot(), blockCoreImportPrefix)
} else { } else {

View File

@ -16,7 +16,7 @@ func TestCheckSafetySkipsRPCCheckForPluginWithoutRPCs(t *testing.T) {
t.Fatalf("currentCMSCoreSDKVersion: %v", err) t.Fatalf("currentCMSCoreSDKVersion: %v", err)
} }
writeTestFile(t, filepath.Join(pluginRoot, "plugin.mod"), "[plugin]\nname = \"example\"\nversion = \"1.0.0\"\n", 0644) writeTestFile(t, filepath.Join(pluginRoot, "plugin.mod"), "[plugin]\nname = \"example\"\nversion = \"1.0.0\"\n", 0644)
writeTestFile(t, filepath.Join(pluginRoot, "go.mod"), "module example.com/plugin\n\ngo 1.26.2\n\nrequire git.dev.alexdunmow.com/block/core "+sdkVersion+"\n", 0644) writeTestFile(t, filepath.Join(pluginRoot, "go.mod"), "module example.com/plugin\n\ngo 1.26.2\n\nrequire git.dev.alexdunmow.com/block/pluginsdk "+sdkVersion+"\n", 0644)
writeTestFile(t, filepath.Join(pluginRoot, "main.go"), "package example\n", 0644) writeTestFile(t, filepath.Join(pluginRoot, "main.go"), "package example\n", 0644)
cwd, err := os.Getwd() cwd, err := os.Getwd()
@ -54,7 +54,7 @@ func TestCheckSafetyTypechecksExternalPluginFrontendWithWorkspaceDeps(t *testing
} }
writeTestFile(t, filepath.Join(pluginRoot, "plugin.mod"), "[plugin]\nname = \"example\"\nversion = \"1.0.0\"\n", 0644) writeTestFile(t, filepath.Join(pluginRoot, "plugin.mod"), "[plugin]\nname = \"example\"\nversion = \"1.0.0\"\n", 0644)
writeTestFile(t, filepath.Join(pluginRoot, "go.mod"), "module example.com/plugin\n\ngo 1.26.2\n\nrequire git.dev.alexdunmow.com/block/core "+sdkVersion+"\n", 0644) writeTestFile(t, filepath.Join(pluginRoot, "go.mod"), "module example.com/plugin\n\ngo 1.26.2\n\nrequire git.dev.alexdunmow.com/block/pluginsdk "+sdkVersion+"\n", 0644)
writeTestFile(t, filepath.Join(pluginRoot, "main.go"), "package example\n", 0644) writeTestFile(t, filepath.Join(pluginRoot, "main.go"), "package example\n", 0644)
writeTestFile(t, filepath.Join(pluginWebDir, "package.json"), "{\n \"name\": \"external-plugin-test\",\n \"private\": true,\n \"type\": \"module\",\n \"dependencies\": {\n \"@block-ninja/ui\": \"workspace:*\"\n }\n}\n", 0644) writeTestFile(t, filepath.Join(pluginWebDir, "package.json"), "{\n \"name\": \"external-plugin-test\",\n \"private\": true,\n \"type\": \"module\",\n \"dependencies\": {\n \"@block-ninja/ui\": \"workspace:*\"\n }\n}\n", 0644)
writeTestFile(t, filepath.Join(pluginWebDir, "tsconfig.json"), "{\n \"compilerOptions\": {\n \"target\": \"ES2020\",\n \"module\": \"ESNext\",\n \"moduleResolution\": \"bundler\",\n \"lib\": [\"ES2020\", \"DOM\", \"DOM.Iterable\"],\n \"jsx\": \"react-jsx\",\n \"strict\": true,\n \"skipLibCheck\": true,\n \"noEmit\": true\n },\n \"include\": [\"*.tsx\", \"*.ts\"]\n}\n", 0644) writeTestFile(t, filepath.Join(pluginWebDir, "tsconfig.json"), "{\n \"compilerOptions\": {\n \"target\": \"ES2020\",\n \"module\": \"ESNext\",\n \"moduleResolution\": \"bundler\",\n \"lib\": [\"ES2020\", \"DOM\", \"DOM.Iterable\"],\n \"jsx\": \"react-jsx\",\n \"strict\": true,\n \"skipLibCheck\": true,\n \"noEmit\": true\n },\n \"include\": [\"*.tsx\", \"*.ts\"]\n}\n", 0644)
@ -122,7 +122,7 @@ func TestCheckSafetyFailsStandalonePluginReplaceDirective(t *testing.T) {
t.Fatalf("currentCMSCoreSDKVersion: %v", err) t.Fatalf("currentCMSCoreSDKVersion: %v", err)
} }
writeTestFile(t, filepath.Join(pluginRoot, "plugin.mod"), "[plugin]\nname = \"example\"\nversion = \"1.0.0\"\n", 0644) writeTestFile(t, filepath.Join(pluginRoot, "plugin.mod"), "[plugin]\nname = \"example\"\nversion = \"1.0.0\"\n", 0644)
writeTestFile(t, filepath.Join(pluginRoot, "go.mod"), "module example.com/plugin\n\ngo 1.26.2\n\nrequire git.dev.alexdunmow.com/block/core "+sdkVersion+"\n\nreplace git.dev.alexdunmow.com/block/core => ../block-core\n", 0644) writeTestFile(t, filepath.Join(pluginRoot, "go.mod"), "module example.com/plugin\n\ngo 1.26.2\n\nrequire git.dev.alexdunmow.com/block/pluginsdk "+sdkVersion+"\n\nreplace git.dev.alexdunmow.com/block/pluginsdk => ../block-pluginsdk\n", 0644)
writeTestFile(t, filepath.Join(pluginRoot, "main.go"), "package example\n", 0644) writeTestFile(t, filepath.Join(pluginRoot, "main.go"), "package example\n", 0644)
cwd, err := os.Getwd() cwd, err := os.Getwd()
@ -150,7 +150,7 @@ func TestCheckSafetyFailsStandalonePluginSQLCUUIDStringOverrides(t *testing.T) {
t.Fatalf("currentCMSCoreSDKVersion: %v", err) t.Fatalf("currentCMSCoreSDKVersion: %v", err)
} }
writeTestFile(t, filepath.Join(pluginRoot, "plugin.mod"), "[plugin]\nname = \"example\"\nversion = \"1.0.0\"\n", 0644) writeTestFile(t, filepath.Join(pluginRoot, "plugin.mod"), "[plugin]\nname = \"example\"\nversion = \"1.0.0\"\n", 0644)
writeTestFile(t, filepath.Join(pluginRoot, "go.mod"), "module example.com/plugin\n\ngo 1.26.2\n\nrequire git.dev.alexdunmow.com/block/core "+sdkVersion+"\n", 0644) writeTestFile(t, filepath.Join(pluginRoot, "go.mod"), "module example.com/plugin\n\ngo 1.26.2\n\nrequire git.dev.alexdunmow.com/block/pluginsdk "+sdkVersion+"\n", 0644)
writeTestFile(t, filepath.Join(pluginRoot, "main.go"), "package example\n", 0644) writeTestFile(t, filepath.Join(pluginRoot, "main.go"), "package example\n", 0644)
writeTestFile(t, filepath.Join(pluginRoot, "sqlc.yaml"), `version: "2" writeTestFile(t, filepath.Join(pluginRoot, "sqlc.yaml"), `version: "2"
sql: sql:
@ -198,7 +198,7 @@ func TestCheckSafetyWarnsOnStandalonePluginGoAnyUsage(t *testing.T) {
t.Fatalf("currentCMSCoreSDKVersion: %v", err) t.Fatalf("currentCMSCoreSDKVersion: %v", err)
} }
writeTestFile(t, filepath.Join(pluginRoot, "plugin.mod"), "[plugin]\nname = \"example\"\nversion = \"1.0.0\"\n", 0644) writeTestFile(t, filepath.Join(pluginRoot, "plugin.mod"), "[plugin]\nname = \"example\"\nversion = \"1.0.0\"\n", 0644)
writeTestFile(t, filepath.Join(pluginRoot, "go.mod"), "module example.com/plugin\n\ngo 1.26.2\n\nrequire git.dev.alexdunmow.com/block/core "+sdkVersion+"\n", 0644) writeTestFile(t, filepath.Join(pluginRoot, "go.mod"), "module example.com/plugin\n\ngo 1.26.2\n\nrequire git.dev.alexdunmow.com/block/pluginsdk "+sdkVersion+"\n", 0644)
writeTestFile(t, filepath.Join(pluginRoot, "main.go"), `package example writeTestFile(t, filepath.Join(pluginRoot, "main.go"), `package example
type Payload struct { type Payload struct {
@ -236,7 +236,7 @@ func TestCheckSafetyFailsStandalonePluginSQLCCompile(t *testing.T) {
t.Fatalf("currentCMSCoreSDKVersion: %v", err) t.Fatalf("currentCMSCoreSDKVersion: %v", err)
} }
writeTestFile(t, filepath.Join(pluginRoot, "plugin.mod"), "[plugin]\nname = \"example\"\nversion = \"1.0.0\"\n", 0644) writeTestFile(t, filepath.Join(pluginRoot, "plugin.mod"), "[plugin]\nname = \"example\"\nversion = \"1.0.0\"\n", 0644)
writeTestFile(t, filepath.Join(pluginRoot, "go.mod"), "module example.com/plugin\n\ngo 1.26.2\n\nrequire git.dev.alexdunmow.com/block/core "+sdkVersion+"\n", 0644) writeTestFile(t, filepath.Join(pluginRoot, "go.mod"), "module example.com/plugin\n\ngo 1.26.2\n\nrequire git.dev.alexdunmow.com/block/pluginsdk "+sdkVersion+"\n", 0644)
writeTestFile(t, filepath.Join(pluginRoot, "main.go"), "package example\n", 0644) writeTestFile(t, filepath.Join(pluginRoot, "main.go"), "package example\n", 0644)
writeTestFile(t, filepath.Join(pluginRoot, "sqlc.yaml"), `version: "2" writeTestFile(t, filepath.Join(pluginRoot, "sqlc.yaml"), `version: "2"
sql: sql:

View File

@ -12,6 +12,7 @@ import (
const ( const (
blockCoreImportPrefix = "git.dev.alexdunmow.com/block/core" blockCoreImportPrefix = "git.dev.alexdunmow.com/block/core"
pluginSDKImportPrefix = "git.dev.alexdunmow.com/block/pluginsdk"
blockNinjaImportPrefix = "git.dev.alexdunmow.com/block/cms" blockNinjaImportPrefix = "git.dev.alexdunmow.com/block/cms"
) )

View File

@ -20,6 +20,17 @@ func currentCMSCoreSDKVersion() (string, error) {
return readRequiredModuleVersion(filepath.Join(blockNinjaRepoRoot(), "backend", "go.mod"), blockCoreImportPrefix) return readRequiredModuleVersion(filepath.Join(blockNinjaRepoRoot(), "backend", "go.mod"), blockCoreImportPrefix)
} }
// currentCMSPluginSDKVersion anchors the fleet's pluginsdk pin to the CMS
// backend's. Empty (no error) while the CMS itself hasn't migrated to
// pluginsdk yet — version enforcement is skipped during that transition.
func currentCMSPluginSDKVersion() (string, error) {
v, err := readRequiredModuleVersion(filepath.Join(blockNinjaRepoRoot(), "backend", "go.mod"), pluginSDKImportPrefix)
if err != nil {
return "", nil
}
return v, nil
}
func parseGoModForSafety(goModPath string) (*modfile.File, []pluginGoModViolation) { func parseGoModForSafety(goModPath string) (*modfile.File, []pluginGoModViolation) {
if !fileExists(goModPath) { if !fileExists(goModPath) {
return nil, []pluginGoModViolation{{ return nil, []pluginGoModViolation{{
@ -157,9 +168,12 @@ func checkStandalonePluginGoMod(root, requiredSDKVersion string) []pluginGoModVi
violations = append(violations, checkGoModForAnyReplaceDirectives(goModPath)...) violations = append(violations, checkGoModForAnyReplaceDirectives(goModPath)...)
// The standalone-plugin SDK is block/pluginsdk (2026-07-07 extraction).
// A block/core require may coexist for the packages that stayed core
// (captcha, backup) — allowed, not required.
currentSDKVersion := "" currentSDKVersion := ""
for _, req := range parsed.Require { for _, req := range parsed.Require {
if req.Mod.Path == blockCoreImportPrefix { if req.Mod.Path == pluginSDKImportPrefix {
currentSDKVersion = req.Mod.Version currentSDKVersion = req.Mod.Version
break break
} }
@ -167,8 +181,8 @@ func checkStandalonePluginGoMod(root, requiredSDKVersion string) []pluginGoModVi
if currentSDKVersion == "" { if currentSDKVersion == "" {
violations = append(violations, pluginGoModViolation{ violations = append(violations, pluginGoModViolation{
file: "go.mod", file: "go.mod",
rule: "missing-block-core-require", rule: "missing-pluginsdk-require",
detail: fmt.Sprintf("missing required module %s", blockCoreImportPrefix), detail: fmt.Sprintf("missing required module %s (standalone plugins build against the plugin SDK, not block/core)", pluginSDKImportPrefix),
}) })
return violations return violations
} }
@ -176,7 +190,7 @@ func checkStandalonePluginGoMod(root, requiredSDKVersion string) []pluginGoModVi
if requiredSDKVersion != "" && currentSDKVersion != requiredSDKVersion { if requiredSDKVersion != "" && currentSDKVersion != requiredSDKVersion {
violations = append(violations, pluginGoModViolation{ violations = append(violations, pluginGoModViolation{
file: "go.mod", file: "go.mod",
rule: "block-core-version-mismatch", rule: "pluginsdk-version-mismatch",
detail: fmt.Sprintf("requires %s, want %s", currentSDKVersion, requiredSDKVersion), detail: fmt.Sprintf("requires %s, want %s", currentSDKVersion, requiredSDKVersion),
}) })
} }

View File

@ -50,9 +50,9 @@ func TestCheckStandalonePluginGoModFlagsReplaceDirectives(t *testing.T) {
go 1.26.2 go 1.26.2
require git.dev.alexdunmow.com/block/core v0.2.1 require git.dev.alexdunmow.com/block/pluginsdk v0.2.1
replace git.dev.alexdunmow.com/block/core => ../block-core replace git.dev.alexdunmow.com/block/pluginsdk => ../block-pluginsdk
`, 0644) `, 0644)
violations := checkStandalonePluginGoMod(root, "v0.2.1") violations := checkStandalonePluginGoMod(root, "v0.2.1")
@ -67,34 +67,79 @@ replace git.dev.alexdunmow.com/block/core => ../block-core
} }
} }
func TestCheckStandalonePluginGoModFlagsOutdatedSDKVersion(t *testing.T) { // A replace directive for the coexisting block/core module still fails —
// replace directives of any module are forbidden in standalone plugin repos.
func TestCheckStandalonePluginGoModFlagsCoreReplaceDirective(t *testing.T) {
root := t.TempDir() root := t.TempDir()
writeTestFile(t, filepath.Join(root, "go.mod"), `module example.com/plugin writeTestFile(t, filepath.Join(root, "go.mod"), `module example.com/plugin
go 1.26.2 go 1.26.2
require git.dev.alexdunmow.com/block/core v0.2.0 require git.dev.alexdunmow.com/block/pluginsdk v0.2.1
replace git.dev.alexdunmow.com/block/core => ../block-core
`, 0644) `, 0644)
violations := checkStandalonePluginGoMod(root, "v0.2.1") violations := checkStandalonePluginGoMod(root, "v0.2.1")
if len(violations) != 1 { if len(violations) != 1 {
t.Fatalf("checkStandalonePluginGoMod() returned %d violations, want 1: %#v", len(violations), violations) t.Fatalf("checkStandalonePluginGoMod() returned %d violations, want 1: %#v", len(violations), violations)
} }
if violations[0].rule != "block-core-version-mismatch" { if violations[0].rule != "no-replace-directives" {
t.Fatalf("rule = %q, want block-core-version-mismatch", violations[0].rule) t.Fatalf("rule = %q, want no-replace-directives", violations[0].rule)
}
}
func TestCheckStandalonePluginGoModFlagsOutdatedSDKVersion(t *testing.T) {
root := t.TempDir()
writeTestFile(t, filepath.Join(root, "go.mod"), `module example.com/plugin
go 1.26.2
require git.dev.alexdunmow.com/block/pluginsdk v0.2.0
`, 0644)
violations := checkStandalonePluginGoMod(root, "v0.2.1")
if len(violations) != 1 {
t.Fatalf("checkStandalonePluginGoMod() returned %d violations, want 1: %#v", len(violations), violations)
}
if violations[0].rule != "pluginsdk-version-mismatch" {
t.Fatalf("rule = %q, want pluginsdk-version-mismatch", violations[0].rule)
} }
if !strings.Contains(violations[0].detail, "want v0.2.1") { if !strings.Contains(violations[0].detail, "want v0.2.1") {
t.Fatalf("detail = %q, want target version", violations[0].detail) t.Fatalf("detail = %q, want target version", violations[0].detail)
} }
} }
func TestCheckStandalonePluginGoModAllowsMatchingSDKVersionWithoutReplace(t *testing.T) { func TestCheckStandalonePluginGoModFlagsMissingPluginSDKRequire(t *testing.T) {
root := t.TempDir() root := t.TempDir()
writeTestFile(t, filepath.Join(root, "go.mod"), `module example.com/plugin writeTestFile(t, filepath.Join(root, "go.mod"), `module example.com/plugin
go 1.26.2 go 1.26.2
require git.dev.alexdunmow.com/block/core v0.2.1 require git.dev.alexdunmow.com/block/core v0.2.1
`, 0644)
violations := checkStandalonePluginGoMod(root, "v0.2.1")
if len(violations) != 1 {
t.Fatalf("checkStandalonePluginGoMod() returned %d violations, want 1: %#v", len(violations), violations)
}
if violations[0].rule != "missing-pluginsdk-require" {
t.Fatalf("rule = %q, want missing-pluginsdk-require", violations[0].rule)
}
}
// A coexisting block/core require is allowed alongside the required pluginsdk
// require (e.g. calcomblock keeps core for captcha).
func TestCheckStandalonePluginGoModAllowsMatchingSDKVersionWithoutReplace(t *testing.T) {
root := t.TempDir()
writeTestFile(t, filepath.Join(root, "go.mod"), `module example.com/plugin
go 1.26.2
require (
git.dev.alexdunmow.com/block/core v0.5.0
git.dev.alexdunmow.com/block/pluginsdk v0.2.1
)
`, 0644) `, 0644)
violations := checkStandalonePluginGoMod(root, "v0.2.1") violations := checkStandalonePluginGoMod(root, "v0.2.1")

View File

@ -18,7 +18,7 @@ func TestRegistryOrder(t *testing.T) {
"1", "2", "2b", "2c", "2d", "2e", "2f", "3", "3b", "4", "1", "2", "2b", "2c", "2d", "2e", "2f", "3", "3b", "4",
"5", "6", "7", "8", "9", "10", "10b", "10disc", "11", "12", "5", "6", "7", "8", "9", "10", "10b", "10disc", "11", "12",
"13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22",
"28", "29", "28", "29", "30", "31",
} }
ordered := make([]Check, len(registry)) ordered := make([]Check, len(registry))

View File

@ -1,2 +1,2 @@
check-safety FIXTURE_DIR check-safety FIXTURE_DIR
32 checks: 20 ok 12 skip -> OK 34 checks: 20 ok 14 skip -> OK

View File

@ -10,4 +10,4 @@ FAIL 15 1 err.Error() leak(s) to HTTP clients — log via slog.Error() and retur
FAIL 17 1 TODO marker(s) found — ship explicit behavior, not placeholders FAIL 17 1 TODO marker(s) found — ship explicit behavior, not placeholders
internal/service/handler.go:14 // TODO: add proper initialisation internal/service/handler.go:14 // TODO: add proper initialisation
32 checks: 14 ok 13 skip 5 fail -> FAIL 34 checks: 14 ok 15 skip 5 fail -> FAIL