Skip to content

v0.1.13

Latest

Choose a tag to compare

@github-actions github-actions released this 03 Sep 19:33
· 3 commits to main since this release
527b159

Security fix: role access rules are now enforced

Severity: high. Before this release, the per-role access rules (service_name, component, verb_mask) were never consulted for API-key requests. Any valid API key could read and write every table of every service, regardless of the role it was bound to. Only the permissions of the underlying database user limited what it could do. The same gap existed for MCP tool calls.

What changed

  • REST requests to /api/v1/{service}/... made with an API key are now checked against the key's role. Rules are evaluated per service, per component (_table/customers, _schema, _proc/name, ...) and per HTTP verb. A request that no rule permits is refused with 403 and an error envelope naming the role, service, component and verb.
  • Enforcement is fail-closed: a role with no rules, a rule with verb_mask = 0, or an inactive role grants nothing. Config-store failures during the check produce 500, never a pass-through.
  • Admin sessions (JWT) are not subject to role rules.
  • Services flagged read_only now reject every non-GET request for everyone, including admins and MCP raw SQL. Previously only DDL calls honoured the flag.
  • MCP tools honour the same rules: faucet_query needs GET, faucet_insert POST, faucet_update PATCH, faucet_delete DELETE, faucet_list_tables GET on _table, faucet_describe_table GET on _schema/{table}. faucet_raw_sql requires all five verbs on a rule whose component matches _sql (for example *). faucet_list_services and tool error hints only name services the role can reach.
  • faucet mcp --transport http now requires the same API key or JWT credentials as the main server. It previously served without authentication. stdio mode runs with local admin privileges.
  • JWT secret: FAUCET_AUTH_JWT_SECRET (alias FAUCET_JWT_SECRET) was silently ignored, so deployments without a config file signed admin tokens with a hard-coded development secret. The env vars now work, and when no secret is configured one is generated once and stored in the data directory. Existing admin sessions must log in again after upgrading unless auth.jwt_secret was set in a config file.
  • Rule patterns match service and table names exactly as they appear in the URL (case-sensitive), because service names and quoted table identifiers are case-sensitive.
  • PUT /api/v1/system/role/{id} no longer deactivates a role when is_active is omitted, and role responses return the stored, normalized rules.
  • faucet serve logs a warning at startup for every role that has active keys but no usable rules.
  • New CLI: faucet role create --verbs GET [--service NAME] [--component PATTERN] and faucet role grant --role NAME --verbs ... [--service ...] [--component ...].
  • The embedded SQLite config store now really runs in WAL mode with a busy timeout (the previous pragma syntax was ignored by the driver), and the per-request last_used write on API keys is throttled to once a minute.
  • The OpenAPI spec documents the 403 response.

Upgrade notes

Roles created with faucet role create before this release have no access rules, so keys bound to them will start receiving 403. Roles created in the admin UI default to GET-only on every service, so keys that used to write through them now need POST, PUT, PATCH or DELETE granted. Grant what is needed, for example:

faucet role grant --role readonly --verbs GET
faucet role grant --role writer --verbs GET,POST,PUT,PATCH,DELETE

or edit the role in the admin UI, or PUT /api/v1/system/role/{id} with an access array. The server logs a warning at startup for each affected role.

Component patterns: * (everything), _table/customers (one table), _table/* (all tables and the table listing), or a bare table name. Verb bits: GET=1, POST=2, PUT=4, PATCH=8, DELETE=16, all=31.

Row-level filters on a rule are stored and returned by the API but are still not applied to queries. That remains a documented gap.


npm

npx @faucetdb/faucet@0.1.13 — published to npm as @faucetdb/faucet 0.1.13 with its six platform packages.

Changelog

  • 73d4aa0 Merge branch 'wt/cli' into fix/rbac-verb-mask-enforcement
  • 3e30939 Merge branch 'wt/core2' into fix/rbac-verb-mask-enforcement
  • 9cc18cb Merge branch 'wt/mcp' into fix/rbac-verb-mask-enforcement
  • 50a66a8 Merge branch 'wt/ops2' into fix/rbac-verb-mask-enforcement
  • d633128 Merge pull request #4 from jonas136/feat/aggregate-group-by
  • 85b521c Update README
  • bf46912 feat(cli): add role grant, --verbs on role create, RBAC docs and 403 in OpenAPI
  • c90ee8e feat(query): add aggregate functions and GROUP BY to the table query API
  • 96e0ae0 fix(cli): generate and persist JWT secret, honor FAUCET_AUTH_JWT_SECRET, warn on unusable roles
  • db3ca39 fix(mcp): enforce read_only on raw SQL, fail closed on store errors, stop leaking service names
  • bc27684 fix(mcp): enforce role access rules for MCP tools and resources
  • 53d1a78 fix(rbac): address review findings — raw SQL honours read_only, exact-case matching, JWT secret handling, startup diagnostics
  • 3e3497e fix(rbac): case-sensitive rule matching, stored-rule responses, sqlite pragmas, last_used throttle
  • 4157d9c fix(rbac): close remaining review findings
  • 527b159 fix(rbac): enforce role verb_mask for API-key requests (REST + MCP) (#6)
  • f8bf572 fix(rbac): enforce role verb_mask on API-key requests
  • 337e9b0 fix(rbac): fail closed on store errors, reject empty verb specs, normalize empty rule patterns
  • c97b615 test(rbac): lock in verb_mask enforcement semantics