admin_suite 0.4.0 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +7 -0
- data/CHANGELOG.md +203 -18
- data/CONTRIBUTING.md +9 -4
- data/README.md +21 -5
- data/app/assets/vendor/chart.umd.min.js +14 -0
- data/app/controllers/admin_suite/application_controller.rb +12 -11
- data/app/controllers/admin_suite/mcp_controller.rb +36 -0
- data/app/controllers/admin_suite/resources_controller.rb +71 -17
- data/app/helpers/admin_suite/base_helper.rb +187 -10
- data/app/javascript/admin_suite_application.js +3 -0
- data/app/javascript/controllers/admin_suite/chart_controller.js +173 -0
- data/app/views/admin_suite/panels/_chart.html.erb +158 -18
- data/app/views/admin_suite/resources/index.html.erb +25 -5
- data/app/views/admin_suite/shared/_sidebar.html.erb +14 -8
- data/app/views/layouts/admin_suite/application.html.erb +6 -0
- data/config/routes.rb +8 -0
- data/lib/admin/base/filter_builder.rb +48 -5
- data/lib/admin/base/resource.rb +46 -32
- data/lib/admin_suite/auth/host_user.rb +42 -0
- data/lib/admin_suite/auth/strategy.rb +1 -1
- data/lib/admin_suite/auth.rb +15 -0
- data/lib/admin_suite/authorization_context.rb +28 -0
- data/lib/admin_suite/configuration.rb +66 -8
- data/lib/admin_suite/engine.rb +1 -1
- data/lib/admin_suite/legacy_custom_renderer_procs.rb +1 -1
- data/lib/admin_suite/mcp/authorization.rb +68 -0
- data/lib/admin_suite/mcp/serializer.rb +138 -0
- data/lib/admin_suite/mcp/tools/aggregate.rb +55 -0
- data/lib/admin_suite/mcp/tools/describe_resources.rb +63 -0
- data/lib/admin_suite/mcp/tools/get_record.rb +41 -0
- data/lib/admin_suite/mcp/tools/list_records.rb +67 -0
- data/lib/admin_suite/mcp.rb +53 -0
- data/lib/admin_suite/query.rb +71 -0
- data/lib/admin_suite/renderer_registry.rb +11 -0
- data/lib/admin_suite/ui/dashboard_definition.rb +6 -0
- data/lib/admin_suite/ui/show_value_formatter.rb +2 -2
- data/lib/admin_suite/version.rb +1 -1
- data/lib/admin_suite.rb +23 -7
- data/lib/generators/admin_suite/install/templates/admin_suite.rb +5 -2
- data/test/controllers/resources_controller_test.rb +19 -13
- data/test/integration/association_linking_test.rb +292 -0
- data/test/integration/authentication_test.rb +10 -0
- data/test/integration/authorization_test.rb +20 -3
- data/test/integration/chart_panel_test.rb +491 -0
- data/test/integration/dashboard_test.rb +9 -2
- data/test/integration/index_query_characterization_test.rb +229 -0
- data/test/integration/index_table_test.rb +289 -0
- data/test/integration/mcp_aggregate_test.rb +44 -0
- data/test/integration/mcp_authorization_test.rb +102 -0
- data/test/integration/mcp_endpoint_test.rb +89 -0
- data/test/integration/mcp_get_record_test.rb +62 -0
- data/test/integration/mcp_instrumentation_test.rb +107 -0
- data/test/integration/mcp_list_records_test.rb +75 -0
- data/test/integration/mcp_parity_test.rb +155 -0
- data/test/integration/mcp_release_test.rb +131 -0
- data/test/integration/navigation_sections_test.rb +21 -0
- data/test/integration/read_only_resource_test.rb +128 -2
- data/test/integration/searchable_select_search_test.rb +369 -0
- data/test/integration/show_hide_blank_test.rb +195 -0
- data/test/integration/toggle_test.rb +106 -0
- data/test/lib/auth_host_user_test.rb +52 -0
- data/test/lib/auth_http_basic_test.rb +10 -0
- data/test/lib/auth_test.rb +20 -3
- data/test/lib/authorization_context_test.rb +127 -0
- data/test/lib/definition_loader_test.rb +12 -0
- data/test/lib/engine_defaults_test.rb +1 -2
- data/test/lib/form_field_renderer_test.rb +83 -11
- data/test/lib/format_table_cell_test.rb +49 -0
- data/test/lib/index_includes_test.rb +223 -0
- data/test/lib/mcp_serializer_test.rb +107 -0
- data/test/lib/query_test.rb +91 -0
- data/test/lib/removed_deprecations_test.rb +16 -0
- data/test/lib/renderer_test.rb +23 -7
- data/test/publish_workflow_test.rb +63 -0
- data/test/test_helper.rb +73 -8
- metadata +76 -9
- data/lib/admin_suite/renderers/legacy_gleania.rb +0 -230
- data/test/lib/legacy_renderer_deprecation_test.rb +0 -35
- data/test/lib/resource_exportable_deprecation_test.rb +0 -39
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 964267328a54fb0d55bfb035fab32ba694b620b0f5cbdb45194e770a3138885f
|
|
4
|
+
data.tar.gz: eec49bd217460a272eb6ce1add0fd9ac487764a37e304bdcde105044f7eed80a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5875a1f28a12afb57b1e43c38db7f4362f6ef896f2b0de7f0af2d949945ac1c60e17f0e24a5b3f967f753fdeac8960470f2076421ef31156f3fb64b03285fbd2
|
|
7
|
+
data.tar.gz: 76e74fce525a385fad34c84511f2affbfeca6df6ea147e81dfdaa393051c3b98915055f1b620040a140c6ce5e336823fc66928d2a0b01ca9017881914d530185
|
data/.gitignore
CHANGED
|
@@ -10,3 +10,10 @@
|
|
|
10
10
|
/test/dummy/storage/
|
|
11
11
|
admin_suite-*.gem
|
|
12
12
|
/.bundle/
|
|
13
|
+
|
|
14
|
+
# Agent scratch: git worktrees created per-phase, and subagent-driven-development
|
|
15
|
+
# ledgers/briefs/review diffs. Never part of the gem — `spec.files` is an
|
|
16
|
+
# allowlist, so these could not ship, but an `add -A` from the repo root would
|
|
17
|
+
# otherwise commit an entire nested worktree.
|
|
18
|
+
/.claude/
|
|
19
|
+
/.superpowers/
|
data/CHANGELOG.md
CHANGED
|
@@ -5,12 +5,196 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
-
## [
|
|
8
|
+
## [0.6.1] - 2026-09-12
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
- Automated gem publishing now uses RubyGems Trusted Publishing (GitHub Actions
|
|
12
|
+
OIDC) instead of a long-lived API key that required an interactive MFA code.
|
|
13
|
+
- Publishing is restricted to successful CI for main-branch pushes from this
|
|
14
|
+
repository, or manual dispatch on main, using the protected `release` environment.
|
|
15
|
+
|
|
16
|
+
### Upgrade notes
|
|
17
|
+
- Includes the changes listed under 0.6.0 below, which was not published to
|
|
18
|
+
RubyGems. Upgrading from 0.5.0 requires the 0.6.0 host authentication,
|
|
19
|
+
authorization, and renderer migrations.
|
|
20
|
+
|
|
21
|
+
## [0.6.0] - 2026-09-09
|
|
22
|
+
|
|
23
|
+
### Breaking
|
|
24
|
+
- `read_only` resources now reject declared member and bulk actions as well as
|
|
25
|
+
CRUD and toggle routes (404, no model mutation).
|
|
26
|
+
- Authorization hooks now accept `context:` instead of `controller:`. Use
|
|
27
|
+
`context.surface` (`:web` or `:mcp`), `context.controller` (web only), and
|
|
28
|
+
`context.request`. Old signatures fail at assignment with migration guidance.
|
|
29
|
+
- Removed the deprecated `exportable` no-op and the four built-in Gleania
|
|
30
|
+
renderer implementations. Hosts must remove `exportable` calls and provide
|
|
31
|
+
their own renderer classes before upgrading. Existing registered host keys work.
|
|
32
|
+
- MCP requires a real actor and an explicit `config.authorize` hook. A nil hook
|
|
33
|
+
exposes no tools/data; authenticated web requests retain their existing behavior.
|
|
34
|
+
- Default DSL page sizes above the configured cap are now capped on the web index too.
|
|
35
|
+
|
|
36
|
+
### Added
|
|
37
|
+
- Operator MCP at `<mount>/mcp`, using the official SDK's stateless HTTP transport.
|
|
38
|
+
Four read tools: `describe_resources`, `list_records`, `get_record`, `aggregate`.
|
|
39
|
+
Discovery includes portal, section, declared fields, and declared actions as
|
|
40
|
+
metadata (actions are not callable). Reads serialize declared fields only;
|
|
41
|
+
association panels require explicit columns and return bounded rows. No write
|
|
42
|
+
tools, LLM calls or chat UI in this release.
|
|
43
|
+
- `:host_user` authentication strategy with a host-provided user resolver; shared
|
|
44
|
+
actor normalization across surfaces. Existing HTTP Basic and SSO still work.
|
|
45
|
+
- Resource DSL `mcp false` opt-out and `config.mcp.enabled` / `max_page_size` settings.
|
|
46
|
+
- `admin_suite.mcp.tool_call` notifications with tool, resource, action,
|
|
47
|
+
actor_type, actor_id, request_id, filters, q, allowed, error, result_count and
|
|
48
|
+
duration_ms. Hosts own request-log persistence.
|
|
49
|
+
|
|
50
|
+
### Fixed
|
|
51
|
+
- MCP index serialization evaluates column content lambdas (matching the web
|
|
52
|
+
index) and coerces times and association records to JSON primitives instead of
|
|
53
|
+
`to_s` heap addresses.
|
|
54
|
+
- MCP/default pagination cannot bypass the configured cap by omitting `per_page`
|
|
55
|
+
or passing invalid/non-positive values. The response states the applied limit.
|
|
56
|
+
- Anonymous MCP calls are rejected even under the development escape hatch;
|
|
57
|
+
`get_record` additionally checks record-level policy before serialization.
|
|
58
|
+
- Foreign browser origins are rejected. Notifications return 202; unsupported
|
|
59
|
+
GET streams and session deletion return 405.
|
|
60
|
+
|
|
61
|
+
### Changed
|
|
62
|
+
- Extracted `AdminSuite::Query`; the web index and MCP share filter/search/sort,
|
|
63
|
+
eager-loading and page-size behavior, covered by parity/characterization tests.
|
|
64
|
+
- Migration guide: `../_vault/products/admin_suite/docs/mcp.md`.
|
|
65
|
+
|
|
66
|
+
## [0.5.0] - 2026-08-01
|
|
67
|
+
|
|
68
|
+
### Added
|
|
69
|
+
- **Charts.** `chart_panel` now renders a real Chart.js chart (Chart.js
|
|
70
|
+
4.5.1, vendored at `app/assets/vendor/chart.umd.min.js` — no gem
|
|
71
|
+
dependency, no CDN, works air-gapped/under a strict CSP), loaded only on
|
|
72
|
+
pages that actually render a chart with data. New `type:` option —
|
|
73
|
+
`:bar` (default), `:line`, `:area` (a Chart.js line chart with
|
|
74
|
+
`fill: true`), or `:doughnut`; an unrecognized value falls back to
|
|
75
|
+
`:bar` and logs a warning rather than raising, regardless of the input's
|
|
76
|
+
type (Symbol, String, Integer, Boolean, ...). New `height:` option (see
|
|
77
|
+
Changed below for the new default). The existing CSS bar chart remains
|
|
78
|
+
the no-JS degraded state — nothing is hidden until Chart.js has actually
|
|
79
|
+
built the real chart. See
|
|
80
|
+
`../_vault/products/admin_suite/docs/charts.md`.
|
|
81
|
+
- Index rows are now clickable end to end via the already-existing (but
|
|
82
|
+
previously unwired) `ClickActionsController`: clicking anywhere on a row
|
|
83
|
+
other than an interactive element (link, button, form input) navigates to
|
|
84
|
+
the record's show page.
|
|
85
|
+
- A 25/50/100 per-page selector in the index's existing filter form,
|
|
86
|
+
clamped server-side to a maximum of 100 regardless of what the
|
|
87
|
+
`per_page` query param requests, falling back to the resource's
|
|
88
|
+
`paginate(n)` value when the param is absent or invalid (non-numeric,
|
|
89
|
+
zero, negative, or array-shaped).
|
|
90
|
+
- `column :name, align: :right` (also `:center`, `:left`) DSL option,
|
|
91
|
+
emitting the matching Tailwind alignment class on the `<td>`.
|
|
92
|
+
- The index's `<thead>` is now `sticky top-0`, and its scroll wrapper is
|
|
93
|
+
now bounded (`max-h-[70vh] overflow-y-auto`, alongside the existing
|
|
94
|
+
`overflow-x-auto`) so the header actually pins **within that scroll
|
|
95
|
+
region** while scrolling a long page of results — not to the browser
|
|
96
|
+
viewport — instead of scrolling away with the page.
|
|
97
|
+
- `index do includes :company, :line_items end` — eager-loads the named
|
|
98
|
+
associations on the index's filtered/sorted/searched scope, before
|
|
99
|
+
pagination. Skips silently on a scope that doesn't support `#includes`;
|
|
100
|
+
logs and degrades (unoptimized, still renders) if `#includes` itself
|
|
101
|
+
raises (e.g. a bad association name). See
|
|
102
|
+
`../_vault/products/admin_suite/docs/resources.md`.
|
|
103
|
+
- A gem-provided JSON search endpoint, `GET <mount>/:portal/:resource/search?q=`,
|
|
104
|
+
for `searchable_select` — hosts no longer need to hand-build one. Enforces
|
|
105
|
+
authentication and `config.authorize` (`action: :read`), only searches the
|
|
106
|
+
resource's declared `searchable` fields, hard-caps at 25 results, and
|
|
107
|
+
returns `[]` (never the whole table) for a blank/missing `q`. New field
|
|
108
|
+
option `resource:` resolves a `searchable_select` field's search URL to
|
|
109
|
+
this endpoint automatically; a String `collection:` still overrides it
|
|
110
|
+
unconditionally. See `../_vault/products/admin_suite/docs/fields.md`.
|
|
111
|
+
- `hide_blank: true` on show `fields:` panels (sidebar or main column) hides
|
|
112
|
+
a field's row entirely instead of rendering a label with an empty value.
|
|
113
|
+
Deliberately stricter than `.blank?`: only `nil`/`""`/`[]`/`{}` are
|
|
114
|
+
hidden — whitespace-only strings, `false`, and `0`/`0.0` are kept, since
|
|
115
|
+
none of those are "no data," and `false`/`0` are today's real rendered
|
|
116
|
+
values for a lot of fields. See
|
|
117
|
+
`../_vault/products/admin_suite/docs/resources.md`.
|
|
118
|
+
|
|
119
|
+
### Changed
|
|
120
|
+
- **Host-visible:** `belongs_to`-shaped values now render as links to the
|
|
121
|
+
associated record's own admin show page — in both index columns
|
|
122
|
+
(previously a raw `#<Company:0x...>` inspect string) and association
|
|
123
|
+
tables (previously plain text). Falls back to plain text (never a raw
|
|
124
|
+
inspect string, never a 500) when no resource is registered for the
|
|
125
|
+
associated class, the record is unpersisted, or its display title
|
|
126
|
+
raises.
|
|
127
|
+
- **Host-visible:** the chart panel's default height changed from a 64px
|
|
128
|
+
strip to **192px**. 64px was enough for a sparkline-style bar row but not
|
|
129
|
+
a real chart with axes/labels; both the degraded bars and the live canvas
|
|
130
|
+
read the same height value, so there's no shift between the two, but
|
|
131
|
+
every existing dashboard's chart panels are now taller unless `height:`
|
|
132
|
+
is set explicitly. `chart_panel`'s markup for hosts overriding
|
|
133
|
+
`config.partials[:panel_chart]` has also changed shape (new Stimulus
|
|
134
|
+
mount + data attributes) — see the charts doc.
|
|
135
|
+
- **Host-visible:** resources declaring `paginate(n)` now render that many
|
|
136
|
+
rows per page instead of Pagy's own default of 20 — see the Fixed entry
|
|
137
|
+
below. Operators may see different row counts and pagination boundaries
|
|
138
|
+
than they're used to.
|
|
139
|
+
- `column.css_class` (populated by the DSL's `class:` option) is now
|
|
140
|
+
applied to the rendered `<td>`. Previously accepted but never read.
|
|
141
|
+
- A column value that is `nil` now renders as `—`, matching every other
|
|
142
|
+
surface in the gem, instead of a blank cell. Applies to both plain
|
|
143
|
+
scalar columns and `belongs_to`-shaped association columns.
|
|
144
|
+
- **Host-visible:** the `pagy` dependency range is now `>= 9.0, < 10`
|
|
145
|
+
(previously `>= 6.0, < 11.0`). `paginate_collection` calls `pagy(scope,
|
|
146
|
+
limit:)` (see the Fixed entry above) — `limit:` is Pagy 9.x's vars key,
|
|
147
|
+
silently ignored on Pagy 6-8, and Pagy 10 reworked the backend API
|
|
148
|
+
again. A host resolving Pagy 6-8 for another reason will now get a real
|
|
149
|
+
bundler resolution conflict at `bundle update` instead of quietly
|
|
150
|
+
reintroducing the "paginate(n) ignored, 20 rows forever" bug this
|
|
151
|
+
release fixes.
|
|
152
|
+
- `turbo-rails` is now an explicit gem dependency. The engine has always
|
|
153
|
+
hard-depended on it (`turbo_frame_tag` in the resource views;
|
|
154
|
+
`format.turbo_stream`/`turbo_stream.replace` in the `toggle` action) —
|
|
155
|
+
this declares what was already true, it does not add a new
|
|
156
|
+
requirement.
|
|
157
|
+
|
|
158
|
+
### Fixed
|
|
159
|
+
- `paginate_collection` called `pagy(scope, items: n)`. Pagy's vars key
|
|
160
|
+
is `limit:`, not `items:` — `items:` silently did nothing, so **every
|
|
161
|
+
resource's `paginate(n)` DSL value has been ignored since the gem's
|
|
162
|
+
first commit**, with every index quietly paginating at Pagy's own
|
|
163
|
+
default of 20 regardless of what was declared. This is a long-standing
|
|
164
|
+
latent bug, not a regression introduced by this release; declared page
|
|
165
|
+
sizes now take effect.
|
|
166
|
+
- A chart panel's `data:` proc raising, returning junk rows (non-Hash
|
|
167
|
+
entries mixed into the array), or returning rows with a non-numeric
|
|
168
|
+
`value` (Boolean, Hash, Array, nil, non-numeric String) all previously
|
|
169
|
+
500'd the dashboard. All three now degrade instead: a raising proc logs
|
|
170
|
+
and shows "No chart data."; junk rows are dropped; junk values render as
|
|
171
|
+
a zero-height bar/slice. String-keyed data rows (e.g. from a JSONB
|
|
172
|
+
column) are also now tolerated the same way `data_table` already
|
|
173
|
+
handles them — previously they rendered blank/zero bars silently rather
|
|
174
|
+
than the real value.
|
|
175
|
+
- A chart panel's `height:` option 500'd the dashboard for any value that
|
|
176
|
+
survives `presence` but doesn't respond to `#to_i` (`true`, a Symbol, a
|
|
177
|
+
non-empty Array or Hash — e.g. `height: :tall` or `height: [200]`). Now
|
|
178
|
+
totally coerced the same way `data:` row values are, falling back to the
|
|
179
|
+
default 192px for anything that doesn't genuinely parse as a number.
|
|
180
|
+
`color:` had the same gap (pre-existing since 0.4.0): any value without
|
|
181
|
+
`#to_sym` (an Integer, Boolean, ...) 500'd the dashboard instead of
|
|
182
|
+
falling through to the existing unknown-color default (indigo).
|
|
183
|
+
|
|
184
|
+
### Deprecated
|
|
185
|
+
- **Unchanged, reiterated for clarity:** the four Gleania-specific renderer
|
|
186
|
+
keys (`:prompt_template_preview`, `:messages_preview`,
|
|
187
|
+
`:tool_args_preview`, `:turn_messages_preview`) and
|
|
188
|
+
`Resource.exportable(*formats)` remain deprecated (as of 0.4.0) and
|
|
189
|
+
**still work in 0.5.0**. Their removal, originally targeted at 0.5.0, is
|
|
190
|
+
now targeted at **0.6.0**, pending the Gleania and TrustGrowth host
|
|
191
|
+
migrations. The runtime deprecation warnings (and their source comments)
|
|
192
|
+
have been retargeted to say 0.6.0 as part of this release.
|
|
9
193
|
|
|
10
194
|
## [0.4.0] - 2026-08-01
|
|
11
195
|
|
|
12
196
|
### Added
|
|
13
|
-
- `AdminSuite::Renderer` base class for
|
|
197
|
+
- `AdminSuite::Renderer` base class for panel renderers, with shared
|
|
14
198
|
primitives (`json_block`, `code_block`, `key_value_list`, `data_table`,
|
|
15
199
|
`badge`, `empty_state`). Host renderers live in `app/admin/renderers/*.rb`
|
|
16
200
|
as `Admin::Renderers::<Key>Renderer` and are autoloaded from a panel's
|
|
@@ -49,12 +233,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
49
233
|
paper only, with no runtime signal.
|
|
50
234
|
- The built-in `:prompt_template_preview`, `:messages_preview`,
|
|
51
235
|
`:tool_args_preview` and `:turn_messages_preview` renderers. They warn once
|
|
52
|
-
per key per process and are **removed in 0.5.0
|
|
236
|
+
per key per process and are **removed in 0.5.0** (removal retargeted to
|
|
237
|
+
0.6.0 — see [0.5.0]).
|
|
53
238
|
- `Resource.exportable(*formats)` — a no-op that warns once per resource
|
|
54
|
-
class, naming the class, and is **removed in 0.5.0
|
|
55
|
-
|
|
56
|
-
behavior); calling it is now
|
|
57
|
-
at resource-definition time.
|
|
239
|
+
class, naming the class, and is **removed in 0.5.0** (removal retargeted
|
|
240
|
+
to 0.6.0 — see [0.5.0]). It was write-only in every prior release (never
|
|
241
|
+
had a reader, never drove any export behavior); calling it is now
|
|
242
|
+
harmless instead of raising `NoMethodError` at resource-definition time.
|
|
58
243
|
|
|
59
244
|
### Fixed
|
|
60
245
|
- A host `Admin::Renderers::<Key>Renderer` class (or an explicit
|
|
@@ -97,6 +282,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
97
282
|
|
|
98
283
|
## [0.3.0] - 2026-07-31
|
|
99
284
|
|
|
285
|
+
### Added
|
|
286
|
+
- Pluggable auth strategies: `AdminSuite::Auth.register`, built-in
|
|
287
|
+
`:http_basic` (ENV or `config.auth_options` credentials, constant-time
|
|
288
|
+
comparison, blank credentials deny).
|
|
289
|
+
- `config.authorize` is now enforced for every resource action with the
|
|
290
|
+
contract `->(actor:, action:, resource:, record:, controller:)`,
|
|
291
|
+
action ∈ :read/:create/:update/:destroy/:execute.
|
|
292
|
+
- `config.skip_host_before_actions` (default `[:require_authentication]`)
|
|
293
|
+
replaces the hardcoded host-filter skip.
|
|
294
|
+
|
|
100
295
|
### Changed (BREAKING)
|
|
101
296
|
- AdminSuite now **fails closed**: with no authentication configured, every
|
|
102
297
|
engine request responds 403. Configure `config.auth_strategy = :http_basic`
|
|
@@ -108,17 +303,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
108
303
|
dedicated bulk-action lookup. Declared member and bulk actions remain
|
|
109
304
|
allowed on `read_only` resources by design.
|
|
110
305
|
- `execute_action` with an unknown action name now responds 404 instead of
|
|
111
|
-
redirecting with an "Action not found
|
|
112
|
-
|
|
113
|
-
### Added
|
|
114
|
-
- Pluggable auth strategies: `AdminSuite::Auth.register`, built-in
|
|
115
|
-
`:http_basic` (ENV or `config.auth_options` credentials, constant-time
|
|
116
|
-
comparison, blank credentials deny).
|
|
117
|
-
- `config.authorize` is now enforced for every resource action with the
|
|
118
|
-
contract `->(actor:, action:, resource:, record:, controller:)`,
|
|
119
|
-
action ∈ :read/:create/:update/:destroy/:execute.
|
|
120
|
-
- `config.skip_host_before_actions` (default `[:require_authentication]`)
|
|
121
|
-
replaces the hardcoded host-filter skip.
|
|
306
|
+
redirecting with an "Action not found" alert.
|
|
122
307
|
|
|
123
308
|
### Fixed
|
|
124
309
|
- `config.current_actor` is now consulted at most once per request
|
data/CONTRIBUTING.md
CHANGED
|
@@ -28,7 +28,7 @@ See `../_vault/products/admin_suite/docs/development.md` for detailed informatio
|
|
|
28
28
|
### CI Checks
|
|
29
29
|
|
|
30
30
|
All pull requests must pass the following checks before merging:
|
|
31
|
-
- **Tests**: Automated test suite runs on Ruby 3.2
|
|
31
|
+
- **Tests**: Automated test suite runs on the latest available patch releases of Ruby 3.2, 3.3, 3.4, and 4.0
|
|
32
32
|
- **Coverage**: Code coverage is automatically generated and uploaded to Codecov
|
|
33
33
|
- **Code Review**: At least one maintainer approval required
|
|
34
34
|
|
|
@@ -40,10 +40,15 @@ See `../_vault/products/admin_suite/docs/releasing.md` for information on how re
|
|
|
40
40
|
|
|
41
41
|
Releases are automated via GitHub Actions when changes are merged to `main` with a version bump.
|
|
42
42
|
|
|
43
|
-
###
|
|
43
|
+
### Publishing Setup for Maintainers
|
|
44
44
|
|
|
45
|
-
|
|
46
|
-
|
|
45
|
+
RubyGems Trusted Publishing authenticates GitHub Actions with short-lived OIDC
|
|
46
|
+
credentials; no `RUBYGEMS_API_KEY` secret is needed. The gem's trusted publisher
|
|
47
|
+
must match `techwright-lab/admin_suite`, workflow `publish.yml`, and environment
|
|
48
|
+
`release`. Restrict the GitHub `release` environment to the `main` branch.
|
|
49
|
+
See the canonical releasing guide linked above for setup and verification.
|
|
50
|
+
|
|
51
|
+
Optional repository secret:
|
|
47
52
|
- **`CODECOV_TOKEN`**: Optional, for uploading code coverage reports to Codecov (workflow continues without it)
|
|
48
53
|
|
|
49
54
|
## Questions?
|
data/README.md
CHANGED
|
@@ -11,6 +11,7 @@ across other products.
|
|
|
11
11
|
- **Portals**: group resources by portal + section, optional per-portal dashboards
|
|
12
12
|
- **Resources DSL**: index (columns/filters/stats), form fields, show panels/associations, actions
|
|
13
13
|
- **Docs viewer**: renders `*.md` from your host app filesystem at `/docs`
|
|
14
|
+
- **Admin MCP**: four read tools derived from resource definitions, under operator authentication and explicit authorization
|
|
14
15
|
- **UI**: baseline CSS + engine Tailwind build; host overrides optional
|
|
15
16
|
|
|
16
17
|
## Documentation
|
|
@@ -43,20 +44,35 @@ bin/rails g admin_suite:install --mount-path=/internal/admin
|
|
|
43
44
|
|
|
44
45
|
### Secure it (recommended)
|
|
45
46
|
|
|
46
|
-
|
|
47
|
+
Resolve the host user and authorize admin access:
|
|
47
48
|
|
|
48
49
|
```ruby
|
|
49
50
|
# config/initializers/admin_suite.rb
|
|
50
51
|
AdminSuite.configure do |config|
|
|
51
|
-
config.
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
end
|
|
52
|
+
config.auth_strategy = :host_user
|
|
53
|
+
config.auth_options = { resolve: ->(controller) { controller.current_user } }
|
|
54
|
+
config.authorize = ->(actor:, action:, resource:, record:, context:) { actor&.admin? }
|
|
55
55
|
end
|
|
56
56
|
```
|
|
57
57
|
|
|
58
58
|
Read more: `../_vault/products/admin_suite/docs/configuration.md`
|
|
59
59
|
|
|
60
|
+
Set `config.authorize` to decide *what* an authenticated actor may do:
|
|
61
|
+
|
|
62
|
+
```ruby
|
|
63
|
+
config.authorize = ->(actor:, action:, resource:, record:, context:) {
|
|
64
|
+
# action is :read, :create, :update, :destroy, or :execute
|
|
65
|
+
true
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
A `false` or `nil` return is `403` (fail closed). Leaving the hook `nil`
|
|
70
|
+
keeps authentication as the only web gate; MCP serves no tools or data. Resources marked `read_only` reject
|
|
71
|
+
CRUD, `toggle`, and named execute/bulk actions regardless of this hook.
|
|
72
|
+
|
|
73
|
+
The MCP endpoint is `<mount>/mcp`. See
|
|
74
|
+
`../_vault/products/admin_suite/docs/mcp.md` for setup, tool contracts and migration.
|
|
75
|
+
|
|
60
76
|
### Add portals (navigation metadata)
|
|
61
77
|
|
|
62
78
|
```ruby
|