admin_suite 0.6.1 → 0.7.0
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 +5 -0
- data/CHANGELOG.md +19 -0
- data/CONTRIBUTING.md +5 -0
- data/Gemfile +1 -0
- data/README.md +18 -7
- data/lib/admin_suite/version.rb +1 -1
- data/test/archspec/enforcement_test.rb +115 -0
- data/test/dummy/config/environments/development.rb +9 -6
- data/test/dummy_boot_test.rb +21 -0
- data/test/lib/action_executor_test.rb +17 -9
- metadata +5 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7ea45471224303ab612d3d27887cd3245fcd1f942c06c4a3108e98e5ee91ca4e
|
|
4
|
+
data.tar.gz: ad3e08e25c5e977ace59521565309f5702fbbfb6ff6d2a20d09630161d659c51
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b971fe2fbd3d44d7b3fc0addefd909c0cde1716442cd80c0e3627ba6bdcbcd3c4a9d42eac9e4dab767fef10c1793279639ec63c32c934682520afd8ea931998e
|
|
7
|
+
data.tar.gz: 7f6f6a1bdbdf194cf5eed18cbe5336c021ab4df544af1c62f0dbc4ad96e6a5c24f503126f50c1702af2bf1c8ab7c2a5ac70ba8fbf5ea6890903292b0190b622d
|
data/.gitignore
CHANGED
|
@@ -10,6 +10,11 @@
|
|
|
10
10
|
/test/dummy/storage/
|
|
11
11
|
admin_suite-*.gem
|
|
12
12
|
/.bundle/
|
|
13
|
+
/site/_site/
|
|
14
|
+
/site/.jekyll-cache/
|
|
15
|
+
/site/.sass-cache/
|
|
16
|
+
/site/.bundle/
|
|
17
|
+
/site/vendor/
|
|
13
18
|
|
|
14
19
|
# Agent scratch: git worktrees created per-phase, and subagent-driven-development
|
|
15
20
|
# ledgers/briefs/review diffs. Never part of the gem — `spec.files` is an
|
data/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,25 @@ 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
|
+
## [0.7.0] - 2026-10-04
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- Public Jekyll documentation with a dark Just the Docs theme, responsive
|
|
12
|
+
navigation, full-text search, and versioned gem metadata.
|
|
13
|
+
- GitHub Pages build and deployment workflow with rendered link, asset, anchor,
|
|
14
|
+
and search checks. Pull requests validate without deploying.
|
|
15
|
+
- Deterministic, allowlisted publication export from canonical vault docs with
|
|
16
|
+
source revision tracking, content hashes, and export drift checks.
|
|
17
|
+
|
|
18
|
+
## [0.6.2] - 2026-10-03
|
|
19
|
+
|
|
20
|
+
### Fixed
|
|
21
|
+
- Restored database-free dummy application boot and executable action coverage.
|
|
22
|
+
- Updated the development dummy application to Ruby 3.4.10.
|
|
23
|
+
|
|
24
|
+
### Changed
|
|
25
|
+
- Added architecture boundary checks and baseline validation to local and hosted CI.
|
|
26
|
+
|
|
8
27
|
## [0.6.1] - 2026-09-12
|
|
9
28
|
|
|
10
29
|
### Fixed
|
data/CONTRIBUTING.md
CHANGED
|
@@ -19,6 +19,11 @@ See `../_vault/products/admin_suite/docs/development.md` for detailed informatio
|
|
|
19
19
|
|
|
20
20
|
## Pull Requests
|
|
21
21
|
|
|
22
|
+
For the public Jekyll site, edit the canonical vault sources and regenerate the
|
|
23
|
+
publication snapshot; do not hand-edit `site/generated/`. See
|
|
24
|
+
`../_vault/products/admin_suite/docs/docs-publication.md` or the
|
|
25
|
+
[published workflow](https://techwright-lab.github.io/admin_suite/docs-publication/).
|
|
26
|
+
|
|
22
27
|
1. Create a feature branch from `main`
|
|
23
28
|
2. Make your changes
|
|
24
29
|
3. Add or update tests as needed
|
data/Gemfile
CHANGED
data/README.md
CHANGED
|
@@ -16,9 +16,21 @@ across other products.
|
|
|
16
16
|
|
|
17
17
|
## Documentation
|
|
18
18
|
|
|
19
|
+
[Read the documentation](https://techwright-lab.github.io/admin_suite/) —
|
|
20
|
+
[Installation](https://techwright-lab.github.io/admin_suite/installation/),
|
|
21
|
+
[Resources](https://techwright-lab.github.io/admin_suite/resources/), and
|
|
22
|
+
[Admin MCP](https://techwright-lab.github.io/admin_suite/mcp/).
|
|
23
|
+
|
|
19
24
|
Canonical AdminSuite documentation lives in the TechWright vault at
|
|
20
25
|
`../_vault/products/admin_suite/docs/`. This repo intentionally has no root
|
|
21
|
-
`docs/` tree or docs symlink.
|
|
26
|
+
`docs/` tree or docs symlink. The Jekyll site in `site/` publishes a generated,
|
|
27
|
+
allowlisted snapshot. See the [publication guide](https://techwright-lab.github.io/admin_suite/docs-publication/)
|
|
28
|
+
or its canonical source, `../_vault/products/admin_suite/docs/docs-publication.md`,
|
|
29
|
+
for export, drift checks, local preview, and GitHub Pages setup.
|
|
30
|
+
|
|
31
|
+
## Architecture check
|
|
32
|
+
|
|
33
|
+
`bin/archspec check` and `bin/archspec-baseline` enforce engine, namespace, and dummy-app boundaries in `Archspec.rb`. They do not boot Rails. Do not grow `archspec_todo.yml`.
|
|
22
34
|
|
|
23
35
|
## Quickstart
|
|
24
36
|
|
|
@@ -55,7 +67,7 @@ AdminSuite.configure do |config|
|
|
|
55
67
|
end
|
|
56
68
|
```
|
|
57
69
|
|
|
58
|
-
Read more:
|
|
70
|
+
Read more: [Configuration](https://techwright-lab.github.io/admin_suite/configuration/).
|
|
59
71
|
|
|
60
72
|
Set `config.authorize` to decide *what* an authenticated actor may do:
|
|
61
73
|
|
|
@@ -71,7 +83,7 @@ keeps authentication as the only web gate; MCP serves no tools or data. Resource
|
|
|
71
83
|
CRUD, `toggle`, and named execute/bulk actions regardless of this hook.
|
|
72
84
|
|
|
73
85
|
The MCP endpoint is `<mount>/mcp`. See
|
|
74
|
-
|
|
86
|
+
[Admin MCP](https://techwright-lab.github.io/admin_suite/mcp/) for setup, tool contracts and migration.
|
|
75
87
|
|
|
76
88
|
### Add portals (navigation metadata)
|
|
77
89
|
|
|
@@ -84,7 +96,7 @@ AdminSuite.configure do |config|
|
|
|
84
96
|
end
|
|
85
97
|
```
|
|
86
98
|
|
|
87
|
-
Read more:
|
|
99
|
+
Read more: [Portals & dashboards](https://techwright-lab.github.io/admin_suite/portals/).
|
|
88
100
|
|
|
89
101
|
### Add a resource
|
|
90
102
|
|
|
@@ -123,7 +135,7 @@ module Admin
|
|
|
123
135
|
end
|
|
124
136
|
```
|
|
125
137
|
|
|
126
|
-
Read more:
|
|
138
|
+
Read more: [Resources](https://techwright-lab.github.io/admin_suite/resources/) and [Fields](https://techwright-lab.github.io/admin_suite/fields/).
|
|
127
139
|
|
|
128
140
|
### Add docs (optional)
|
|
129
141
|
|
|
@@ -133,7 +145,7 @@ Then visit:
|
|
|
133
145
|
|
|
134
146
|
- `/internal/admin/docs`
|
|
135
147
|
|
|
136
|
-
Read more:
|
|
148
|
+
Read more: [Docs viewer](https://techwright-lab.github.io/admin_suite/docs-viewer/).
|
|
137
149
|
|
|
138
150
|
## Contributing
|
|
139
151
|
|
|
@@ -142,4 +154,3 @@ See:
|
|
|
142
154
|
- `CONTRIBUTING.md`
|
|
143
155
|
- `../_vault/products/admin_suite/docs/development.md`
|
|
144
156
|
- `../_vault/products/admin_suite/docs/releasing.md`
|
|
145
|
-
|
data/lib/admin_suite/version.rb
CHANGED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "minitest/autorun" unless defined?(Rails)
|
|
4
|
+
require "yaml"
|
|
5
|
+
require "open3"
|
|
6
|
+
require "tmpdir"
|
|
7
|
+
require "fileutils"
|
|
8
|
+
|
|
9
|
+
class ArchspecEnforcementTest < Minitest::Test
|
|
10
|
+
ROOT = File.expand_path("../..", __dir__)
|
|
11
|
+
|
|
12
|
+
def test_pull_request_architecture_job_is_fail_closed_and_matches_bin_ci
|
|
13
|
+
workflow = YAML.load_file(File.join(ROOT, ".github/workflows/ci.yml"))
|
|
14
|
+
job = workflow.fetch("jobs").fetch("architecture")
|
|
15
|
+
assert_equal "ubuntu-latest", job["runs-on"]
|
|
16
|
+
assert_nil job["continue-on-error"]
|
|
17
|
+
assert_nil job["if"]
|
|
18
|
+
|
|
19
|
+
commands = job.fetch("steps").filter_map { |step| step["run"] }
|
|
20
|
+
assert_includes commands, "bin/archspec check"
|
|
21
|
+
assert_includes commands, "bin/archspec-baseline"
|
|
22
|
+
assert commands.none? { |command| command.include?("continue-on-error") || command.include?("[ -f") }
|
|
23
|
+
|
|
24
|
+
ci = File.read(File.join(ROOT, "bin/ci"))
|
|
25
|
+
assert_includes ci, 'step "Architecture: ArchSpec" bin/archspec check'
|
|
26
|
+
assert_includes ci, 'step "Architecture: baseline cap" bin/archspec-baseline'
|
|
27
|
+
refute_match(/if \[ -f bin\/archspec \]/, ci)
|
|
28
|
+
refute_match(/if \[ -f Archspec\.rb \]/, ci)
|
|
29
|
+
assert_equal "read", job.dig("permissions", "contents")
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def test_mcp_cannot_call_rejects_a_write
|
|
33
|
+
spec = File.read(File.join(ROOT, "Archspec.rb"))
|
|
34
|
+
rule = spec[/mcp\.cannot_call\b.*?receiver: :any/m]
|
|
35
|
+
assert rule, "mcp.cannot_call must forbid writes on any receiver"
|
|
36
|
+
refute_match(/ui\.cannot_call/, rule)
|
|
37
|
+
assert_match(/queries\.cannot_use\b[^\n]*:mcp\b/, spec)
|
|
38
|
+
|
|
39
|
+
Dir.mktmpdir do |dir|
|
|
40
|
+
FileUtils.mkdir_p(File.join(dir, "lib/admin_suite/mcp"))
|
|
41
|
+
File.write(File.join(dir, "Archspec.rb"), spec)
|
|
42
|
+
File.write(File.join(dir, "archspec_todo.yml"), File.read(File.join(ROOT, "archspec_todo.yml")))
|
|
43
|
+
File.write(File.join(dir, "lib/admin_suite/mcp/probe.rb"), <<~RUBY)
|
|
44
|
+
module AdminSuite
|
|
45
|
+
module Mcp
|
|
46
|
+
class Probe
|
|
47
|
+
def call(record)
|
|
48
|
+
record.save
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
RUBY
|
|
54
|
+
|
|
55
|
+
output, status = run_archspec(dir, "check")
|
|
56
|
+
refute status.success?, output
|
|
57
|
+
assert_match(/must not call #save/, output)
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def test_missing_and_invalid_configuration_fail
|
|
62
|
+
Dir.mktmpdir do |dir|
|
|
63
|
+
_output, status = run_archspec(dir, "check", "--config", File.join(dir, "missing.rb"))
|
|
64
|
+
refute status.success?
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
Dir.mktmpdir do |dir|
|
|
68
|
+
File.write(File.join(dir, "Archspec.rb"), "this is not ruby (\n")
|
|
69
|
+
_output, status = run_archspec(dir, "check")
|
|
70
|
+
refute status.success?
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def test_stale_baseline_id_fails_and_current_set_passes
|
|
75
|
+
Dir.mktmpdir do |dir|
|
|
76
|
+
FileUtils.mkdir_p(File.join(dir, "app/models"))
|
|
77
|
+
File.write(File.join(dir, "app/models/widget.rb"), "class Widget\nend\n")
|
|
78
|
+
File.write(File.join(dir, "Archspec.rb"), <<~CONFIG)
|
|
79
|
+
todo "archspec_todo.yml"
|
|
80
|
+
component :models, in: "app/models/**/*.rb"
|
|
81
|
+
models.cannot_reference_constants "Nope"
|
|
82
|
+
CONFIG
|
|
83
|
+
File.write(File.join(dir, "archspec_todo.yml"), <<~YAML)
|
|
84
|
+
---
|
|
85
|
+
violations: []
|
|
86
|
+
YAML
|
|
87
|
+
|
|
88
|
+
_output, status = run_baseline(dir)
|
|
89
|
+
assert status.success?, "empty matching baseline must pass"
|
|
90
|
+
|
|
91
|
+
File.write(File.join(dir, "archspec_todo.yml"), <<~YAML)
|
|
92
|
+
---
|
|
93
|
+
violations:
|
|
94
|
+
- id: deadbeefdeadbeefdeadbeef
|
|
95
|
+
rule: constants.forbid
|
|
96
|
+
path: app/models/widget.rb
|
|
97
|
+
line: 1
|
|
98
|
+
message: gone
|
|
99
|
+
YAML
|
|
100
|
+
output, status = run_baseline(dir)
|
|
101
|
+
refute status.success?
|
|
102
|
+
assert_match(/stale deadbeefdeadbeefdeadbeef/, output)
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
private
|
|
107
|
+
|
|
108
|
+
def run_archspec(dir, *args)
|
|
109
|
+
Open3.capture2e({ "BUNDLE_GEMFILE" => File.join(ROOT, "Gemfile") }, File.join(ROOT, "bin/archspec"), *args, chdir: dir)
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def run_baseline(dir)
|
|
113
|
+
Open3.capture2e({ "BUNDLE_GEMFILE" => File.join(ROOT, "Gemfile") }, File.join(ROOT, "bin/archspec-baseline"), chdir: dir)
|
|
114
|
+
end
|
|
115
|
+
end
|
|
@@ -31,14 +31,17 @@ Rails.application.configure do
|
|
|
31
31
|
# Print deprecation notices to the Rails logger.
|
|
32
32
|
config.active_support.deprecation = :log
|
|
33
33
|
|
|
34
|
-
#
|
|
35
|
-
config.active_record
|
|
34
|
+
# The dummy app can run without the Active Record railtie.
|
|
35
|
+
if config.respond_to?(:active_record)
|
|
36
|
+
# Raise an error on page load if there are pending migrations.
|
|
37
|
+
config.active_record.migration_error = :page_load
|
|
36
38
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
+
# Highlight code that triggered database queries in logs.
|
|
40
|
+
config.active_record.verbose_query_logs = true
|
|
39
41
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
+
# Append comments with runtime information tags to SQL queries in logs.
|
|
43
|
+
config.active_record.query_log_tags_enabled = true
|
|
44
|
+
end
|
|
42
45
|
|
|
43
46
|
# Highlight code that triggered redirect in logs.
|
|
44
47
|
config.action_dispatch.verbose_redirect_logs = true
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "test_helper"
|
|
4
|
+
require "open3"
|
|
5
|
+
require "rbconfig"
|
|
6
|
+
|
|
7
|
+
class DummyBootTest < ActiveSupport::TestCase
|
|
8
|
+
test "database-free dummy boots and eager loads in development" do
|
|
9
|
+
script = <<~RUBY
|
|
10
|
+
require_relative "test/dummy/config/environment"
|
|
11
|
+
abort "Unexpected ActiveRecord railtie" if Rails.application.config.respond_to?(:active_record)
|
|
12
|
+
Rails.application.eager_load!
|
|
13
|
+
RUBY
|
|
14
|
+
stdout, stderr, status = Open3.capture3(
|
|
15
|
+
{ "RAILS_ENV" => "development" }, RbConfig.ruby, "-e", script,
|
|
16
|
+
chdir: File.expand_path("..", __dir__)
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
assert status.success?, "Development boot failed:\n#{stdout}#{stderr}"
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
require "test_helper"
|
|
4
4
|
require "tmpdir"
|
|
5
|
+
require "open3"
|
|
6
|
+
require "rbconfig"
|
|
5
7
|
|
|
6
8
|
module Admin
|
|
7
9
|
module Base
|
|
@@ -96,16 +98,22 @@ module Admin
|
|
|
96
98
|
end
|
|
97
99
|
|
|
98
100
|
test "load_action_handlers_for_admin_suite returns early when AdminSuite is not defined" do
|
|
99
|
-
#
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
101
|
+
# Bundler evaluates the gemspec and defines AdminSuite::VERSION.
|
|
102
|
+
# Bypass its RUBYOPT preload in this dependency-free subprocess.
|
|
103
|
+
script = <<~RUBY
|
|
104
|
+
require_relative "lib/admin/base/action_executor"
|
|
105
|
+
abort "AdminSuite unexpectedly loaded" if defined?(AdminSuite)
|
|
106
|
+
executor = Admin::Base::ActionExecutor.new(nil, :test, nil)
|
|
107
|
+
result = executor.send(:load_action_handlers_for_admin_suite!)
|
|
108
|
+
abort "Expected early return" unless result.nil?
|
|
109
|
+
abort "Handlers marked loaded" if Admin::Base::ActionExecutor.handlers_loaded
|
|
110
|
+
RUBY
|
|
111
|
+
stdout, stderr, status = Open3.capture3(
|
|
112
|
+
{ "RUBYOPT" => nil }, RbConfig.ruby, "--disable-gems", "-e", script,
|
|
113
|
+
chdir: File.expand_path("../..", __dir__)
|
|
114
|
+
)
|
|
106
115
|
|
|
107
|
-
|
|
108
|
-
assert_nil executor.send(:load_action_handlers_for_admin_suite!)
|
|
116
|
+
assert status.success?, "Isolated executor failed:\n#{stdout}#{stderr}"
|
|
109
117
|
end
|
|
110
118
|
|
|
111
119
|
test "load_action_handlers_for_admin_suite handles empty action_globs gracefully" do
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: admin_suite
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.7.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- TechWright Labs
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-10-03 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rails
|
|
@@ -262,6 +262,7 @@ files:
|
|
|
262
262
|
- lib/generators/admin_suite/scaffold/scaffold_generator.rb
|
|
263
263
|
- lib/tasks/admin_suite_tailwind.rake
|
|
264
264
|
- lib/tasks/admin_suite_test.rake
|
|
265
|
+
- test/archspec/enforcement_test.rb
|
|
265
266
|
- test/controllers/resources_controller_test.rb
|
|
266
267
|
- test/dummy/Gemfile
|
|
267
268
|
- test/dummy/README.md
|
|
@@ -305,6 +306,7 @@ files:
|
|
|
305
306
|
- test/dummy/public/icon.svg
|
|
306
307
|
- test/dummy/public/robots.txt
|
|
307
308
|
- test/dummy/test/test_helper.rb
|
|
309
|
+
- test/dummy_boot_test.rb
|
|
308
310
|
- test/fixtures/docs/progress/PROGRESS_REPORT.md
|
|
309
311
|
- test/integration/association_linking_test.rb
|
|
310
312
|
- test/integration/authentication_test.rb
|
|
@@ -359,6 +361,7 @@ licenses:
|
|
|
359
361
|
- MIT
|
|
360
362
|
metadata:
|
|
361
363
|
rubygems_mfa_required: 'true'
|
|
364
|
+
documentation_uri: https://techwright-lab.github.io/admin_suite/
|
|
362
365
|
source_code_uri: https://github.com/techwright-lab/admin_suite
|
|
363
366
|
changelog_uri: https://github.com/techwright-lab/admin_suite/blob/main/CHANGELOG.md
|
|
364
367
|
post_install_message:
|