enola-guides 0.2.1 → 0.3.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/CHANGELOG.md +8 -0
- data/README.md +1 -1
- data/lib/enola-guides.rb +1 -1
- data/recipes/README.md +32 -0
- data/recipes/api-boundaries.yaml +25 -0
- data/recipes/background-work.yaml +21 -0
- data/recipes/data-ownership.yaml +13 -0
- data/recipes/tenant-foreign-key.yaml +12 -0
- metadata +5 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b72117b0db442295ba7133b5328977a4e182bea8d32551298d831f804de8d25e
|
|
4
|
+
data.tar.gz: 1e30af4f9ea75f6562b2084f62dca453ac7036853d8fbba43924eb56ff54d3b5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3136e1557b6cee67baeaf92112514cbffd36fe9af031784557986a97903889636dedcc7bd9b107264af190d9c5ded9a40642df5ec8642404aa16b78c7cc5fa01
|
|
7
|
+
data.tar.gz: c9f373fb525b4ad29c5edd78791abce11cf4e2feaedd3d71625e5b618393494908dcb297132e128e2af505c33cd68758fc6d4c3dd3c73c8c168f47c2482d42ec
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.3.0 (2026-08-23)
|
|
4
|
+
|
|
5
|
+
The recipe catalogue munola binds: `data-ownership`, `api-boundaries`,
|
|
6
|
+
`background-work` and the `tenant-foreign-key` template beside
|
|
7
|
+
`ember-conventions`, each law an existing enola form with the number it held
|
|
8
|
+
at on a real monolith in the catalogue table; every file lints clean bound
|
|
9
|
+
to a Rails tree.
|
|
10
|
+
|
|
3
11
|
## 0.2.1 (2026-08-23)
|
|
4
12
|
|
|
5
13
|
enola v0.4.4 released the constraints program the guides describe
|
data/README.md
CHANGED
|
@@ -74,7 +74,7 @@ your agent's skills folder; the hooks they pair with are under
|
|
|
74
74
|
## Templates and recipes
|
|
75
75
|
|
|
76
76
|
[`templates/`](templates): the CI check script and its comment renderer,
|
|
77
|
-
a cluster configuration, a constraints starter. [`recipes/`](recipes/README.md):
|
|
77
|
+
a cluster configuration, a constraints starter. [`recipes/`](recipes/README.md) (the catalogue munola binds, each recipe with the number its laws held at):
|
|
78
78
|
recipes a repository copies into its own `enola/recipes/` and binds in one
|
|
79
79
|
line, starting with the Ember conventions and a house-recipe template;
|
|
80
80
|
starting points the team reviews, never defaults the tool applies.
|
data/lib/enola-guides.rb
CHANGED
data/recipes/README.md
CHANGED
|
@@ -40,6 +40,27 @@ breach. Start with ratchet.
|
|
|
40
40
|
|
|
41
41
|
## The recipes
|
|
42
42
|
|
|
43
|
+
The catalogue munola binds with one command. Each law is an existing enola
|
|
44
|
+
form; each recipe is here because its laws held on a real Rails monolith at
|
|
45
|
+
a number a team can act on, given beside it.
|
|
46
|
+
|
|
47
|
+
| Recipe | States | Held at | Placement |
|
|
48
|
+
|---|---|---|---|
|
|
49
|
+
| `rails-conventions` (upstream) | jobs, models, serializers and components never render; policies and mailers never enqueue; request API stays in controllers | five of seven laws with zero exceptions, three advisory at 134 crossings | embedded in enola |
|
|
50
|
+
| `rails-strict` (upstream) | the above plus no cycles among the Rails roles and independent concerns | 0 of 127 concerns breach | embedded in enola |
|
|
51
|
+
| `vanilla-rails` (upstream) | the directories the vanilla arrangement leaves empty stay empty | an arrangement a team chooses | embedded in enola |
|
|
52
|
+
| `ember-conventions.yaml` | nine Ember conventions selected by what the code carries | the neutral eight hold; the house ones stay out | embedded in munola |
|
|
53
|
+
| `data-ownership.yaml` | readers read the store only | advisory; bind your query objects | embedded in munola |
|
|
54
|
+
| `api-boundaries.yaml` | the public API is reached only by controllers; a mutating action reaches a policy | 736 unauthorized mutations reported, advisory | embedded in munola |
|
|
55
|
+
| `background-work.yaml` | maintenance tasks live in their namespace and never reach controllers | 0 of 3,250 task call edges reach a controller | embedded in munola |
|
|
56
|
+
| `tenant-foreign-key.yaml` | a table carrying the tenant column carries the foreign key | 3,720 declared, 0 new | written by munola with the column filled in |
|
|
57
|
+
|
|
58
|
+
Two data-ownership laws, one owner per table and storage stays home, are
|
|
59
|
+
declarations rather than recipe rules for now: they live as worked examples
|
|
60
|
+
under [`examples/laws/`](../examples/laws/README.md) because recipe expansion
|
|
61
|
+
in the current release does not rebind the part a graph law names. They join
|
|
62
|
+
`data-ownership.yaml` when it does.
|
|
63
|
+
|
|
43
64
|
- `ember-conventions.yaml`: nine Ember conventions a team can adopt as laws,
|
|
44
65
|
selected by what the code carries (a decorator, a written field, a base
|
|
45
66
|
class's module) rather than by where it sits. Two optional roles are
|
|
@@ -47,6 +68,17 @@ breach. Start with ratchet.
|
|
|
47
68
|
tracked functions in your app) and `fixture-setup` (the entry points of
|
|
48
69
|
your fixture library in tests).
|
|
49
70
|
|
|
71
|
+
- `data-ownership.yaml`: readers (your query objects, bound by you) reach
|
|
72
|
+
the store and nothing else.
|
|
73
|
+
- `api-boundaries.yaml`: the API layer is entered through controllers, and a
|
|
74
|
+
mutating action reaches a policy; bind `mutating-actions` to the part your
|
|
75
|
+
routes reach with POST, PUT, PATCH or DELETE.
|
|
76
|
+
- `background-work.yaml`: maintenance tasks live in the `Maintenance`
|
|
77
|
+
namespace the runner resolves, and never reach controllers.
|
|
78
|
+
- `tenant-foreign-key.yaml`: a template; replace `TENANT_COLUMN` and
|
|
79
|
+
`TENANT_TABLE` (munola's generator does) and every table carrying the
|
|
80
|
+
column must carry the key.
|
|
81
|
+
|
|
50
82
|
Laws whose far end is a helper of your own (a promise-unwrapping getter
|
|
51
83
|
helper, an async-relationship reader) belong in your repository's recipe
|
|
52
84
|
beside these, with your names in them.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
recipe: api-boundaries
|
|
2
|
+
roles:
|
|
3
|
+
- name: controllers
|
|
4
|
+
match: ["app/controllers/**"]
|
|
5
|
+
- name: policies
|
|
6
|
+
match: ["app/policies/**"]
|
|
7
|
+
- name: public-api
|
|
8
|
+
match: ["app/controllers/api/**"]
|
|
9
|
+
- name: mutating-actions
|
|
10
|
+
optional: true
|
|
11
|
+
rules:
|
|
12
|
+
- id: public-api-reached-only-by-controllers
|
|
13
|
+
protect: public-api
|
|
14
|
+
owners: [controllers]
|
|
15
|
+
via: calls
|
|
16
|
+
mode: advisory
|
|
17
|
+
because: "The API layer is entered through a request so that authentication, rate limits and serialization run once, at the edge; an internal caller that reaches an API class directly skips all three and nobody reading the API can see it."
|
|
18
|
+
|
|
19
|
+
- id: mutations-are-authorized
|
|
20
|
+
require_edge: mutating-actions
|
|
21
|
+
to: policies
|
|
22
|
+
direction: outbound
|
|
23
|
+
via: calls
|
|
24
|
+
mode: advisory
|
|
25
|
+
because: "Every write passes a policy before it touches a record. Bind the actions that routes reach with POST, PUT, PATCH or DELETE (a part declared with handles: on those methods) and the law names each mutating action that reaches no policy."
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
recipe: background-work
|
|
2
|
+
roles:
|
|
3
|
+
- name: tasks
|
|
4
|
+
match: ["app/tasks/**"]
|
|
5
|
+
- name: task-classes
|
|
6
|
+
match: ["app/tasks/**"]
|
|
7
|
+
kind: symbol
|
|
8
|
+
where: { symbol_kind: "class" }
|
|
9
|
+
- name: controllers
|
|
10
|
+
match: ["app/controllers/**"]
|
|
11
|
+
rules:
|
|
12
|
+
- id: maintenance-tasks-live-in-their-namespace
|
|
13
|
+
require_name: task-classes
|
|
14
|
+
pattern: "Maintenance::*"
|
|
15
|
+
because: "The task runner resolves task constants from that namespace, which is the one its generator creates, so a task declared outside it never appears in the runner and cannot be run by anyone."
|
|
16
|
+
|
|
17
|
+
- id: maintenance-tasks-never-reach-controllers
|
|
18
|
+
forbid: tasks
|
|
19
|
+
to: controllers
|
|
20
|
+
via: calls
|
|
21
|
+
because: "A task runs from the runner or the console with no request around it, so controller code reached from one has nothing to read."
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
recipe: data-ownership
|
|
2
|
+
roles:
|
|
3
|
+
- name: store
|
|
4
|
+
match: ["app/models/**"]
|
|
5
|
+
- name: readers
|
|
6
|
+
optional: true
|
|
7
|
+
rules:
|
|
8
|
+
- id: readers-read-the-store-only
|
|
9
|
+
allow: readers
|
|
10
|
+
only: [store]
|
|
11
|
+
via: calls
|
|
12
|
+
mode: advisory
|
|
13
|
+
because: "A reader derives its answer from the store alone, which is what keeps it replayable against a snapshot; a reader that reaches a service or a client answers differently on a different machine. Bind your query objects or report classes as the readers."
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
recipe: tenant-foreign-key
|
|
2
|
+
roles:
|
|
3
|
+
- name: tables
|
|
4
|
+
match: ["db/schema.rb", "db/structure.sql", "app/models/**"]
|
|
5
|
+
kind: storage
|
|
6
|
+
rules:
|
|
7
|
+
- id: tenant-foreign-key
|
|
8
|
+
require: tables
|
|
9
|
+
when_prop_contains: { prop: columns, value: TENANT_COLUMN }
|
|
10
|
+
must_prop_contain: { prop: fk_constraints, value: "TENANT_COLUMN->TENANT_TABLE" }
|
|
11
|
+
mode: advisory
|
|
12
|
+
because: "A table carrying the tenant column references the tenant, so the database should say so with a foreign key; a row that outlives its tenant is the leak nobody notices until an export. Advisory while a backfill path that ships the column before the constraint is reconciled with the rule; the verdict names every table that carries the column without the key."
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: enola-guides
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Muhamed Isabegovic
|
|
@@ -115,8 +115,12 @@ files:
|
|
|
115
115
|
- guides/12-the-wrapper.md
|
|
116
116
|
- lib/enola-guides.rb
|
|
117
117
|
- recipes/README.md
|
|
118
|
+
- recipes/api-boundaries.yaml
|
|
119
|
+
- recipes/background-work.yaml
|
|
120
|
+
- recipes/data-ownership.yaml
|
|
118
121
|
- recipes/ember-conventions.yaml
|
|
119
122
|
- recipes/house-recipe-template.yaml
|
|
123
|
+
- recipes/tenant-foreign-key.yaml
|
|
120
124
|
- templates/constraints-starter/background-jobs-never-invoke-controller-code.rb
|
|
121
125
|
- templates/constraints-starter/models-do-not-reach-controllers.rb
|
|
122
126
|
- templates/constraints-starter/policies-only-answer.rb
|