Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 32 additions & 8 deletions .github/wiki/guides/ci/Reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,16 +113,23 @@ A flag is read from the source file that defines it. `verb *` means the flag is

| Flag | Commands |
|---|---|
| `--accepts` | `nodes *` |
| `--addr` | `serve` |
| `--agent-addr` | `serve *` |
| `--agent-binary` | `nodes *` |
| `--agent-source` | `providers github init` |
| `--agent-url` | `nodes pair` |
| `--alert` | `doctor` |
| `--all` | `nodes *` |
| `--allow-deploy-host` | `nodes *` |
| `--allow-downgrade` | `nodes *` |
| `--allow-private` | `providers *` |
| `--allow-unsandboxed` | `serve` |
| `--allowed-repos` | `serve` |
| `--api-addr` | `serve *` |
| `--api-lock` | `serve *` |
| `--api-public-url` | `serve *` |
| `--api-socket` | `serve *` |
| `--api-submit-role` | `serve *` |
| `--app-id` | `policy protect` |
| `--apply` | `runs *` |
Expand All @@ -134,24 +141,26 @@ A flag is read from the source file that defines it. `verb *` means the flag is
| `--binary` | `serve *` |
| `--branch` | `policy protect` |
| `--by` | `config ignore add` |
| `--cert` | `nodes *` |
| `--cert-ttl` | `nodes pair` |
| `--check` | `providers *`, `runs reproduce` |
| `--class` | `nodes *` |
| `--clear` | `policy *` |
| `--cmd` | `nodes sync` |
| `--concurrency` | `serve` |
| `--config` | `explain`, `plan` |
| `--config` | `config *`, `explain`, `plan` |
| `--confirm-flaky` | `runs *` |
| `--container` | - |
| `--coordinator` | `artifacts *`, `runs *` |
| `--coordinator` | `artifacts *`, `nodes *`, `runs *` |
| `--coordinator-id` | `nodes pair` |
| `--data-dir` | `nodes pair`, `serve *` |
| `--dest` | `artifacts *` |
| `--detach` | - |
| `--dir` | `providers *` |
| `--drain-deadline` | `serve *` |
| `--dry-run` | `artifacts *`, `nodes sync`, `policy protect`, `runs *`, `serve *` |
| `--effective` | `policy *` |
| `--enroll-addr` | `nodes pair` |
| `--enroll-addr` | `nodes pair`, `serve *` |
| `--env` | `run` |
| `--env-file` | `serve *` |
| `--f` | `logs` |
Expand All @@ -164,18 +173,20 @@ A flag is read from the source file that defines it. `verb *` means the flag is
| `--gateway` | `run` |
| `--h` | - |
| `--help` | - |
| `--home` | `config *` |
| `--hook` | `policy protect` |
| `--host-key` | `nodes *` |
| `--image` | - |
| `--in` | `serve *` |
| `--init` | `artifacts signer` |
| `--inputs` | `providers gitlab init` |
| `--insecure` | `serve` |
| `--installer` | `nodes *` |
| `--interactive` | `nodes *` |
| `--interval` | `serve watch` |
| `--isolation` | - |
| `--job` | `runs rerun` |
| `--json` | `artifacts *`, `evidence *`, `explain`, `forgejo`, `logs`, `nodes *`, `plan`, `policy *`, `providers *`, `runs *`, `serve *` |
| `--json` | `artifacts *`, `config *`, `doctor`, `evidence *`, `explain`, `forgejo`, `logs`, `nodes *`, `plan`, `policy *`, `providers *`, `runs *`, `serve *` |
| `--keep` | `runs *` |
| `--kek` | `serve *` |
| `--key-id` | `nodes *` |
Expand All @@ -187,40 +198,52 @@ A flag is read from the source file that defines it. `verb *` means the flag is
| `--local` | `nodes status` |
| `--max-age-days` | `runs *` |
| `--max-log-bytes` | `runs *` |
| `--max-queue` | - |
| `--mode` | `nodes *` |
| `--name` | `artifacts *` |
| `--name` | `artifacts *`, `nodes *` |
| `--network` | - |
| `--no-gitleaks` | - |
| `--no-status` | - |
| `--no-status` | `config *` |
| `--node-admin-routes` | `serve *` |
| `--node-key` | `nodes *` |
| `--nodes` | `doctor` |
| `--older-than` | `artifacts *` |
| `--on-battery` | `nodes *` |
| `--once` | `serve watch` |
| `--out` | `artifacts *`, `serve *` |
| `--owner` | `build` |
| `--ownership` | `nodes *` |
| `--persistence` | `nodes *` |
| `--pipeline` | `evidence *`, `explain`, `plan` |
| `--policy` | `evidence *` |
| `--post-status` | - |
| `--prefer` | - |
| `--privacy-zone` | `nodes *` |
| `--probe` | `netproxy` |
| `--project` | `artifacts *`, `nodes *`, `providers *`, `runs *`, `serve admin roles` |
| `--providers` | `doctor` |
| `--proxy` | `netproxy` |
| `--pubkey` | `serve admin audit checkpoint` |
| `--public` | `artifacts signer` |
| `--public-url` | `nodes pair`, `serve *` |
| `--reason` | `config ignore add` |
| `--release` | `artifacts *` |
| `--release-routes` | `serve *` |
| `--remove` | `nodes label` |
| `--repo` | `artifacts verify`, `build`, `config ignore add`, `evidence *`, `explain`, `plan`, `policy *`, `providers *`, `runs *`, `serve *` |
| `--repo` | `artifacts verify`, `build`, `config *`, `doctor`, `evidence *`, `explain`, `plan`, `policy *`, `providers *`, `runs *`, `serve *` |
| `--repos` | `serve watch` |
| `--reserve-cpu` | `nodes *` |
| `--reserve-mem` | `nodes *` |
| `--restore` | `policy protect` |
| `--role` | `serve admin roles` |
| `--rotate` | `artifacts signer` |
| `--run` | `artifacts *`, `logs`, `runs reproduce` |
| `--runner` | - |
| `--scope` | `policy *` |
| `--secret` | `serve` |
| `--secret-classes` | `nodes *` |
| `--self` | `serve *` |
| `--selftest` | `doctor` |
| `--service` | - |
| `--sha` | `runs *` |
| `--shell` | `runs reproduce` |
Expand All @@ -234,7 +257,7 @@ A flag is read from the source file that defines it. `verb *` means the flag is
| `--systemd` | `serve *` |
| `--tag` | `build` |
| `--team` | `policy *`, `serve *` |
| `--timeout` | `build`, `run`, `runs wait`, `serve` |
| `--timeout` | `build`, `config *`, `nodes discover`, `run`, `runs wait`, `serve` |
| `--trigger` | `explain`, `plan` |
| `--trust` | - |
| `--ttl` | `serve *` |
Expand All @@ -248,6 +271,7 @@ A flag is read from the source file that defines it. `verb *` means the flag is
| `--version` | `nodes *` |
| `--where` | - |
| `--workdir` | `serve` |
| `--write` | `config *` |
| `--yes` | `artifacts key` |
<!-- END GENERATED:commands -->

Expand Down
1 change: 1 addition & 0 deletions .github/wiki/plugins/CI.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

| Command | MCP tool | HTTP route | Side effect | Output | Exposure | Confirmation |
|---|---|---|---|---|---|---|
| `nself ci` | `nself_ci` | `/v1/commands/ci` | remote | document | MCP and HTTP | nonce |
| `nself ci artifacts` | `nself_ci_artifacts` | `/v1/commands/ci/artifacts` | read | document | MCP and HTTP | none |
| `nself ci build` | - | - | remote | document | CLI only (json none) | none |
| `nself ci config ignore add` | - | - | write | document | CLI only (json none) | none |
Expand Down
1 change: 1 addition & 0 deletions .github/wiki/plugins/Functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

| Command | MCP tool | HTTP route | Side effect | Output | Exposure | Confirmation |
|---|---|---|---|---|---|---|
| `nself functions` | `nself_functions` | `/v1/commands/functions` | write | document | MCP and HTTP | none |
| `nself functions delete` | `nself_functions_delete` | `/v1/commands/functions/delete` | destructive | document | MCP and HTTP | nonce |
| `nself functions deploy` | `nself_functions_deploy` | `/v1/commands/functions/deploy` | write | document | MCP and HTTP | none |
| `nself functions invoke` | `nself_functions_invoke` | `/v1/commands/functions/invoke` | write | document | MCP and HTTP | none |
Expand Down
1 change: 1 addition & 0 deletions .github/wiki/plugins/Infra.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

| Command | MCP tool | HTTP route | Side effect | Output | Exposure | Confirmation |
|---|---|---|---|---|---|---|
| `nself infra` | - | - | remote | document | CLI only (json none) | none |
| `nself infra apply` | - | - | remote | document | CLI only (surface cli-only) | none |
| `nself infra destroy` | - | - | destructive | document | CLI only (surface cli-only) | none |
| `nself infra plan` | - | - | read | document | CLI only (json legacy) | none |
Expand Down
1 change: 1 addition & 0 deletions .github/wiki/plugins/K8s.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

| Command | MCP tool | HTTP route | Side effect | Output | Exposure | Confirmation |
|---|---|---|---|---|---|---|
| `nself k8s` | - | - | remote | document | CLI only (json legacy) | none |
| `nself k8s backup` | - | - | write | document | CLI only (json legacy) | none |
| `nself k8s install` | - | - | remote | document | CLI only (json legacy) | none |
| `nself k8s restore` | - | - | destructive | document | CLI only (json legacy) | none |
Expand Down
1 change: 1 addition & 0 deletions .github/wiki/plugins/Plugin-Dev.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

| Command | MCP tool | HTTP route | Side effect | Output | Exposure | Confirmation |
|---|---|---|---|---|---|---|
| `nself plugin-dev` | `nself_plugin_dev` | `/v1/commands/plugin-dev` | write | document | MCP and HTTP | none |
| `nself plugin-dev debug` | - | - | write | document | CLI only (surface cli-only) | none |
| `nself plugin-dev dev` | - | - | write | stream | CLI only (surface cli-only) | none |
| `nself plugin-dev init` | - | - | write | document | CLI only (surface cli-only) | none |
Expand Down
1 change: 1 addition & 0 deletions .github/wiki/plugins/Sentry-CLI.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

| Command | MCP tool | HTTP route | Side effect | Output | Exposure | Confirmation |
|---|---|---|---|---|---|---|
| `nself sentry` | `nself_sentry` | `/v1/commands/sentry` | read | document | MCP and HTTP | none |
| `nself sentry alerts channels` | `nself_sentry_alerts_channels` | `/v1/commands/sentry/alerts/channels` | read | document | MCP and HTTP | none |
| `nself sentry alerts test` | - | - | remote | document | CLI only (remote without confirm) | none |
| `nself sentry incidents ack` | `nself_sentry_incidents_ack` | `/v1/commands/sentry/incidents/ack` | write | document | MCP and HTTP | none |
Expand Down
1 change: 1 addition & 0 deletions .github/wiki/plugins/nSelf-Eval-Gate.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

| Command | MCP tool | HTTP route | Side effect | Output | Exposure | Confirmation |
|---|---|---|---|---|---|---|
| `nself eval` | - | - | remote | document | CLI only (json none) | none |
| `nself eval gate` | - | - | read | document | CLI only (json legacy) | none |

<!-- END GENERATED:machine-surface -->
Expand Down
153 changes: 123 additions & 30 deletions free/ci/tools/refgen/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
// flagDefs maps a FlagSet method to the index of its name argument.
var flagDefs = map[string]int{
"Bool": 0, "String": 0, "Int": 0, "Int64": 0, "Uint": 0, "Float64": 0, "Duration": 0,
"Func": 0, "BoolFunc": 0,
"BoolVar": 1, "StringVar": 1, "IntVar": 1, "Int64Var": 1, "UintVar": 1, "Float64Var": 1, "DurationVar": 1, "Var": 1,
}

Expand All @@ -28,7 +29,93 @@ type FlagRow struct {
Commands []string
}

// flagRows returns the flags of the cmd package, sorted by name.
// flagPackages lists the packages outside cmd that define flags of a verb,
// with the verb that owns them: `nodes add` builds its FlagSet in
// internal/nodes/lifecycle, and serve flags are added by packages through
// coordinator.RegisterFlag. TestNoFlagDefinedOutsideScannedPackages fails
// when another package defines a flag, so a flag is never silently omitted.
var flagPackages = map[string]string{
modulePath + "/internal/nodes/lifecycle": "nodes",
modulePath + "/internal/coordinator/drain": "serve",
modulePath + "/internal/config": "config",
modulePath + "/internal/doctor": "doctor",
modulePath + "/internal/discovery": "nodes discover",
}

// listenerVerb owns every flag registered with coordinator.RegisterListener:
// the listener flags are serve flags whichever file registers them.
const listenerVerb = "serve"

// fileFlagNames returns the flag names a file defines on a FlagSet.
func fileFlagNames(m *module, p *pkg, f *srcFile) ([]string, error) {
var names []string
var bad error
ast.Inspect(f.ast, func(n ast.Node) bool {
call, ok := n.(*ast.CallExpr)
if !ok {
return true
}
sel, ok := call.Fun.(*ast.SelectorExpr)
if !ok {
return true
}
i, ok := flagDefs[sel.Sel.Name]
if !ok || len(call.Args) <= i || len(call.Args) < 2 {
return true
}
name, ok := m.str(p, f, call.Args[i], nil)
if !ok {
if _, lit := call.Args[i].(*ast.BasicLit); lit {
bad = fmt.Errorf("%s: flag name not resolvable", f.name)
}
return true
}
names = append(names, name)
return true
})
return names, bad
}

// listenerFlagNames returns the flag names a file registers through
// RegisterListener(name, flag, ...), expanding a range over a literal list
// (`for _, l := range []struct{...}{...} { RegisterListener(l.name, l.flag, ...) }`).
// A flag name it cannot resolve is an error: the table would silently lose a flag.
func listenerFlagNames(m *module, p *pkg, f *srcFile) ([]string, error) {
var names []string
var bad error
w := walker{m: m, p: p, f: f}
w.walk(f.ast, nil, nil, func(call *ast.CallExpr, env map[string][]string, it map[string]string) {
sel, ok := call.Fun.(*ast.SelectorExpr)
if !ok || sel.Sel.Name != "RegisterListener" || len(call.Args) < 2 {
return
}
got := m.strs(p, f, call.Args[1], env)
if s, ok := call.Args[1].(*ast.SelectorExpr); ok && len(got) == 0 {
if v, ok := it[s.Sel.Name]; ok {
got = []string{v}
}
}
if len(got) == 0 {
bad = fmt.Errorf("%s: RegisterListener flag name not resolvable", f.name)
return
}
names = append(names, got...)
})
return names, bad
}

// ownersOfVerb returns the keys of the commands that are verb or start with it.
func ownersOfVerb(cmds []Command, verb string) []string {
var out []string
for _, c := range cmds {
if c.Key == verb || strings.HasPrefix(c.Key, verb+" ") {
out = append(out, c.Key)
}
}
return out
}

// flagRows returns the flags of the cmd package and of flagPackages, sorted by name.
func flagRows(m *module, cmds []Command) ([]FlagRow, error) {
p := m.pkgs[modulePath+"/cmd"]
if p == nil {
Expand All @@ -41,6 +128,15 @@ func flagRows(m *module, cmds []Command) ([]FlagRow, error) {
}
}
got := map[string]map[string]bool{}
add := func(name string, owners []string) {
if got[name] == nil {
got[name] = map[string]bool{}
}
for _, o := range owners {
got[name][o] = true
}
}
serve := ownersOfVerb(cmds, listenerVerb)
for _, f := range p.files {
owners := byFile[f.name]
if len(owners) == 0 {
Expand All @@ -54,37 +150,34 @@ func flagRows(m *module, cmds []Command) ([]FlagRow, error) {
}
}
}
var bad error
ast.Inspect(f.ast, func(n ast.Node) bool {
call, ok := n.(*ast.CallExpr)
if !ok {
return true
}
sel, ok := call.Fun.(*ast.SelectorExpr)
if !ok {
return true
}
i, ok := flagDefs[sel.Sel.Name]
if !ok || len(call.Args) <= i || len(call.Args) < 2 {
return true
}
name, ok := m.str(p, f, call.Args[i], nil)
if !ok {
if _, lit := call.Args[i].(*ast.BasicLit); lit {
bad = fmt.Errorf("%s: flag name not resolvable", f.name)
}
return true
}
if got[name] == nil {
got[name] = map[string]bool{}
names, err := fileFlagNames(m, p, f)
if err != nil {
return nil, err
}
for _, n := range names {
add(n, owners)
}
if names, err = listenerFlagNames(m, p, f); err != nil {
return nil, err
}
for _, n := range names {
add(n, serve)
}
}
for path, verb := range flagPackages {
ep := m.pkgs[path]
if ep == nil {
return nil, fmt.Errorf("flag package %s not found", path)
}
owners := ownersOfVerb(cmds, verb)
for _, f := range ep.files {
names, err := fileFlagNames(m, ep, f)
if err != nil {
return nil, err
}
for _, o := range owners {
got[name][o] = true
for _, n := range names {
add(n, owners)
}
return true
})
if bad != nil {
return nil, bad
}
}
var out []FlagRow
Expand Down
Loading
Loading