Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

feat: add lint check for API key scope enum completeness#19862

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
Show file tree
Hide file tree
Changes fromall 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
7 changes: 6 additions & 1 deletionMakefile
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -561,7 +561,7 @@ endif

# Note: we don't run zizmor in the lint target because it takes a while. CI
# runs it explicitly.
lint: lint/shellcheck lint/go lint/ts lint/examples lint/helm lint/site-icons lint/markdown lint/actions/actionlint
lint: lint/shellcheck lint/go lint/ts lint/examples lint/helm lint/site-icons lint/markdown lint/actions/actionlint lint/check-scopes
.PHONY: lint

lint/site-icons:
Expand DownExpand Up@@ -614,6 +614,11 @@ lint/actions/zizmor:
.
.PHONY: lint/actions/zizmor

# Verify api_key_scope enum contains all RBAC <resource>:<action> values.
lint/check-scopes: coderd/database/dump.sql
go run ./scripts/check-scopes
.PHONY: lint/check-scopes

# All files generated by the database should be added here, and this can be used
# as a target for jobs that need to run after the database is generated.
DB_GEN_FILES := \
Expand Down
43 changes: 43 additions & 0 deletionsscripts/check-scopes/README.md
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
# check-scopes

Validates that the DB enum `api_key_scope` contains every `<resource>:<action>` derived from `coderd/rbac/policy/RBACPermissions`.

- Exits 0 when all scopes are present in `coderd/database/dump.sql`.
- Exits 1 and prints missing values with suggested `ALTER TYPE` statements otherwise.

## Usage

Ensure the schema dump is up-to-date, then run the check:

```sh
make -B gen/db # forces DB dump regeneration
make lint/check-scopes
```

Or directly:

```sh
go run ./tools/check-scopes
```

Optional flags:

- `-dump path` — override path to `dump.sql` (default `coderd/database/dump.sql`).

## Remediation

When the tool reports missing values:

1. Create a DB migration extending the enum, e.g.:

```sql
ALTER TYPE api_key_scope ADD VALUE IF NOT EXISTS 'template:view_insights';
```

2. Regenerate and re-run:

```sh
make -B gen/db && make lint/check-scopes
```

3. Decide whether each new scope is public (exposed in the catalog) or internal-only (handled by the catalog task).
117 changes: 117 additions & 0 deletionsscripts/check-scopes/main.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
package main

import (
"bufio"
"flag"
"fmt"
"os"
"regexp"
"sort"
"strings"

"golang.org/x/xerrors"

"github.com/coder/coder/v2/coderd/rbac/policy"
)

// defaultDumpPath is the repo-relative path to the generated schema dump.
const defaultDumpPath = "coderd/database/dump.sql"

var dumpPathFlag = flag.String("dump", defaultDumpPath, "path to dump.sql (defaults to coderd/database/dump.sql)")

func main() {
flag.Parse()

want := expectedFromRBAC()
have, err := enumValuesFromDump(*dumpPathFlag)
if err != nil {
_, _ = fmt.Fprintf(os.Stderr, "check-scopes: error reading dump: %v\n", err)
os.Exit(2)
}

// Compute missing: want - have
var missing []string
for k := range want {
if _, ok := have[k]; !ok {
missing = append(missing, k)
}
}
sort.Strings(missing)

if len(missing) == 0 {
_, _ = fmt.Println("check-scopes: OK — all RBAC <resource>:<action> values exist in api_key_scope enum")
return
}

_, _ = fmt.Fprintln(os.Stderr, "check-scopes: missing enum values:")
for _, m := range missing {
_, _ = fmt.Fprintf(os.Stderr, " - %s\n", m)
}
_, _ = fmt.Fprintln(os.Stderr)
_, _ = fmt.Fprintln(os.Stderr, "To fix: add a DB migration extending the enum, e.g.:")
for _, m := range missing {
_, _ = fmt.Fprintf(os.Stderr, " ALTER TYPE api_key_scope ADD VALUE IF NOT EXISTS '%s';\n", m)
}
_, _ = fmt.Fprintln(os.Stderr)
_, _ = fmt.Fprintln(os.Stderr, "Also decide if each new scope is public (exposed in the catalog) or internal-only (catalog task).")
os.Exit(1)
}

// expectedFromRBAC returns the set of <resource>:<action> pairs derived from RBACPermissions.
func expectedFromRBAC() map[string]struct{} {
want := make(map[string]struct{})
for resource, def := range policy.RBACPermissions {
if resource == policy.WildcardSymbol {
// Ignore wildcard entry; it has no concrete <resource>:<action> pairs.
continue
}
for action := range def.Actions {
key := resource + ":" + string(action)
want[key] = struct{}{}
}
}
return want
}

// enumValuesFromDump parses dump.sql and extracts all literals from the
// `CREATE TYPE api_key_scope AS ENUM (...)` block.
func enumValuesFromDump(path string) (map[string]struct{}, error) {
f, err := os.Open(path)
if err != nil {
return nil, err
}
defer f.Close()

const enumHead = "CREATE TYPE api_key_scope AS ENUM ("
litRe := regexp.MustCompile(`'([^']+)'`)

values := make(map[string]struct{})
inEnum := false
s := bufio.NewScanner(f)
for s.Scan() {
line := strings.TrimSpace(s.Text())
if !inEnum {
if strings.Contains(line, enumHead) {
inEnum = true
}
continue
}
if strings.HasPrefix(line, ");") {
// End of enum block
return values, nil
}
// Collect single-quoted literals on this line.
for _, m := range litRe.FindAllStringSubmatch(line, -1) {
if len(m) > 1 {
values[m[1]] = struct{}{}
}
}
}
if err := s.Err(); err != nil {
return nil, err
}
if !inEnum {
return nil, xerrors.New("api_key_scope enum block not found in dump")
}
return values, nil
}
Loading

[8]ページ先頭

©2009-2025 Movatter.jp