fiber_audit 0.2.1 → 0.3.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/.fiber-audit.example.yml +7 -8
- data/ARCHITECTURE.md +97 -673
- data/CHANGELOG.md +52 -0
- data/README.md +163 -86
- data/lib/fiber_audit/cli.rb +19 -5
- data/lib/fiber_audit/configuration.rb +31 -6
- data/lib/fiber_audit/operation_semantics.rb +172 -0
- data/lib/fiber_audit/operation_vocabulary.rb +2 -1
- data/lib/fiber_audit/runtime/active_operations.rb +39 -9
- data/lib/fiber_audit/runtime/boot.rb +4 -0
- data/lib/fiber_audit/runtime/environment.rb +58 -0
- data/lib/fiber_audit/runtime/execution_context.rb +55 -43
- data/lib/fiber_audit/runtime/lifecycle.rb +91 -50
- data/lib/fiber_audit/runtime/operation_liveness_monitor.rb +282 -0
- data/lib/fiber_audit/runtime/operation_liveness_policy.rb +47 -0
- data/lib/fiber_audit/runtime/probes/base.rb +27 -4
- data/lib/fiber_audit/runtime/probes/subprocess.rb +89 -8
- data/lib/fiber_audit/runtime/probes/thread_state.rb +0 -14
- data/lib/fiber_audit/runtime/scheduler_evidence_classifier.rb +60 -0
- data/lib/fiber_audit/runtime/scheduler_observer.rb +54 -18
- data/lib/fiber_audit/runtime/scheduler_snapshot.rb +95 -0
- data/lib/fiber_audit/runtime/watchdog.rb +54 -4
- data/lib/fiber_audit/runtime.rb +5 -0
- data/lib/fiber_audit/static/call_site_extractor.rb +1 -0
- data/lib/fiber_audit/static/rules/base.rb +19 -0
- data/lib/fiber_audit/static/rules/blocking_subprocess.rb +67 -10
- data/lib/fiber_audit/static/rules/direct_socket.rb +54 -19
- data/lib/fiber_audit/static/rules/io_select.rb +6 -6
- data/lib/fiber_audit/static/rules/net_http_in_request.rb +11 -8
- data/lib/fiber_audit/static/rules/synchronization.rb +13 -8
- data/lib/fiber_audit/static/rules/thread_current_state.rb +20 -30
- data/lib/fiber_audit/static/rules/thread_join.rb +9 -7
- data/lib/fiber_audit/version.rb +1 -1
- metadata +6 -1
data/ARCHITECTURE.md
CHANGED
|
@@ -1,726 +1,150 @@
|
|
|
1
1
|
# FiberAudit Architecture
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
FiberAudit audits Ruby and Rails applications for operations that may require cooperation from a Fiber scheduler. It publishes static hypotheses and bounded runtime evidence, but it does **not** prove that an application is fiber-safe and never emits an unconditional `PASS`.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
running in a fiber-scheduled environment, such as a Rails application served by
|
|
7
|
-
Falcon.
|
|
5
|
+
> **Repository status:** The static pipeline, explicit runtime probes, Rails execution context, truthful nullable scheduler snapshots, scheduler watchdog, operation-liveness monitor, shared operation semantics, and scalar scheduler classification are implemented. Combined static/runtime reporting remains future work.
|
|
8
6
|
|
|
9
|
-
|
|
7
|
+
The gem installation requirement is Ruby `>= 3.3`. The tested platform contract is CRuby 3.3, 3.4, and 4.0 on Ubuntu Linux. Other engines and operating systems are not currently tested, and native Rubydex package availability remains a platform prerequisite.
|
|
10
8
|
|
|
11
|
-
|
|
12
|
-
2. Where do those operations occur?
|
|
13
|
-
3. Do they appear in request, middleware, callback, job, WebSocket, boot, or
|
|
14
|
-
other execution contexts?
|
|
15
|
-
4. How strong is the evidence for each finding?
|
|
16
|
-
5. What should an application owner review or remediate?
|
|
17
|
-
|
|
18
|
-
FiberAudit does **not** prove that an application is fiber-safe. Static analysis
|
|
19
|
-
produces hypotheses, while observational runtime sessions provide bounded evidence
|
|
20
|
-
without establishing complete coverage. FiberAudit never claims unconditional
|
|
21
|
-
`PASS`.
|
|
22
|
-
|
|
23
|
-
> **Repository status:** v0.2.1 includes the v0.1.0 static pipeline end to end:
|
|
24
|
-
> project discovery, configuration, semantic and syntax analysis, execution
|
|
25
|
-
> contexts, FA1001–FA1007, suppressions, status derivation, text/JSON reports,
|
|
26
|
-
> and the CLI. The v0.2 runtime contracts, bounded JSONL recorder, explicit
|
|
27
|
-
> child-process boot, lifecycle, supervising command, bounded scheduler
|
|
28
|
-
> watchdog, targeted FA1001–FA1007 operation probes, and Rails runtime execution
|
|
29
|
-
> contexts are implemented; static/runtime correlation remains future work.
|
|
30
|
-
|
|
31
|
-
## 2. Scope
|
|
32
|
-
|
|
33
|
-
### v0.1.0
|
|
34
|
-
|
|
35
|
-
The v0.1.0 architecture is static-only:
|
|
36
|
-
|
|
37
|
-
- inspect Ruby source with Rubydex and Prism;
|
|
38
|
-
- identify high-signal operations that may block or misuse thread-local state;
|
|
39
|
-
- classify findings by execution context where possible;
|
|
40
|
-
- attach severity, confidence, evidence, remediation, and a stable fingerprint;
|
|
41
|
-
- apply inline and YAML suppressions;
|
|
42
|
-
- emit text and versioned JSON reports;
|
|
43
|
-
- return CI-friendly exit codes.
|
|
44
|
-
|
|
45
|
-
### Explicitly outside v0.1.0
|
|
46
|
-
|
|
47
|
-
The following belong to later releases:
|
|
48
|
-
|
|
49
|
-
- runtime instrumentation and scheduler watchdogs;
|
|
50
|
-
- Rails Railties and middleware;
|
|
51
|
-
- Falcon process orchestration;
|
|
52
|
-
- static/runtime correlation beyond stable fingerprint generation;
|
|
53
|
-
- dependency compatibility intelligence;
|
|
54
|
-
- SARIF and HTML reporters;
|
|
55
|
-
- runtime-backed `PASS` certification.
|
|
56
|
-
|
|
57
|
-
## 3. Sources of Truth
|
|
58
|
-
|
|
59
|
-
Current code and specs define implementation truth. This document records the
|
|
60
|
-
supported architecture and dependency boundaries; README and CHANGELOG record
|
|
61
|
-
the user-facing release contract.
|
|
62
|
-
|
|
63
|
-
The corrected platform target is Ruby `>= 3.3` with CI configured for Ruby 3.3
|
|
64
|
-
and 3.4. Ruby 3.2 is excluded because it is end-of-life.
|
|
65
|
-
|
|
66
|
-
## 4. Architectural Principles
|
|
67
|
-
|
|
68
|
-
### 4.1 FiberAudit owns its public contracts
|
|
69
|
-
|
|
70
|
-
Rubydex and Prism are implementation dependencies. Their objects must not leak
|
|
71
|
-
into rules, findings, suppressions, or reporters. Adapters translate external
|
|
72
|
-
library data into FiberAudit-owned value objects.
|
|
73
|
-
|
|
74
|
-
### 4.2 Severity and confidence are separate
|
|
75
|
-
|
|
76
|
-
- **Severity** represents impact if the finding is real.
|
|
77
|
-
- **Confidence** represents the strength of the evidence.
|
|
78
|
-
|
|
79
|
-
A high-impact heuristic can therefore be `severity: :high` and
|
|
80
|
-
`confidence: :low` without conflating the two dimensions.
|
|
81
|
-
|
|
82
|
-
### 4.3 Findings are the integration boundary
|
|
83
|
-
|
|
84
|
-
Static rules—and future runtime correlation—use the same `Finding` model.
|
|
85
|
-
Suppressions, status derivation, reporters, and future correlation operate on
|
|
86
|
-
findings rather than AST or semantic-index objects.
|
|
87
|
-
|
|
88
|
-
### 4.4 Analysis degrades gracefully
|
|
89
|
-
|
|
90
|
-
An unresolved constant, unknown execution context, or unsupported Rubydex query
|
|
91
|
-
should lower confidence or produce explicit gap metadata. It should not crash an
|
|
92
|
-
entire project audit unless analysis cannot continue safely.
|
|
93
|
-
|
|
94
|
-
### 4.5 Suppression is post-analysis filtering
|
|
95
|
-
|
|
96
|
-
Rules produce findings independently of suppression policy. The suppression
|
|
97
|
-
store partitions findings into active and suppressed sets. Suppressed findings
|
|
98
|
-
remain available for reporting and audit history, but do not determine the
|
|
99
|
-
active result or exit status.
|
|
100
|
-
|
|
101
|
-
### 4.6 Static analysis cannot grant `PASS`
|
|
102
|
-
|
|
103
|
-
The strongest static-only outcomes are `NO_FINDINGS` or
|
|
104
|
-
`PASS_WITH_WARNINGS`, accompanied by a static-only disclaimer. A plain `PASS`
|
|
105
|
-
requires sufficient runtime coverage and is outside v0.1.0.
|
|
106
|
-
|
|
107
|
-
## 5. System Context
|
|
108
|
-
|
|
109
|
-
```text
|
|
110
|
-
Ruby/Rails project
|
|
111
|
-
source files
|
|
112
|
-
configuration
|
|
113
|
-
suppressions
|
|
114
|
-
|
|
|
115
|
-
v
|
|
116
|
-
+--------------------------+
|
|
117
|
-
| FiberAudit static audit |
|
|
118
|
-
| |
|
|
119
|
-
| Rubydex semantic data |
|
|
120
|
-
| Prism syntax data |
|
|
121
|
-
| Context classification |
|
|
122
|
-
| Static rules |
|
|
123
|
-
| Findings + suppressions |
|
|
124
|
-
+-------------+------------+
|
|
125
|
-
|
|
|
126
|
-
+--> Text report
|
|
127
|
-
+--> JSON report
|
|
128
|
-
+--> Process exit code
|
|
129
|
-
```
|
|
130
|
-
|
|
131
|
-
FiberAudit does not load Rails at the gem entry point. Rails-shaped semantics
|
|
132
|
-
are inferred from source structure, inheritance, paths, and callbacks.
|
|
133
|
-
|
|
134
|
-
## 6. Current Repository Architecture
|
|
135
|
-
|
|
136
|
-
```text
|
|
137
|
-
fiber-audit static
|
|
138
|
-
|
|
|
139
|
-
+-- Project + Configuration
|
|
140
|
-
+-- SemanticIndex + CallSiteExtractor
|
|
141
|
-
+-- ExecutionContextResolver
|
|
142
|
-
+-- Built-in registry (FA1001–FA1007)
|
|
143
|
-
+-- Findings + Suppression Store
|
|
144
|
-
+-- Audit::Result
|
|
145
|
-
+-- Text or JSON reporter
|
|
146
|
-
+-- Exit code 0, 1, or 2
|
|
147
|
-
```
|
|
148
|
-
|
|
149
|
-
### Current component status
|
|
9
|
+
## Component status
|
|
150
10
|
|
|
151
11
|
| Component | Responsibility | Status |
|
|
152
12
|
|---|---|---|
|
|
153
13
|
| Gem packaging and loader | Ruby baseline, executable, public surface | Implemented |
|
|
154
14
|
| CLI and project discovery | Commands, root/config resolution, exit codes | Implemented |
|
|
155
15
|
| Findings and fingerprints | Evidence-bearing values and stable identity | Implemented |
|
|
156
|
-
| Configuration and suppressions |
|
|
157
|
-
|
|
|
158
|
-
|
|
|
159
|
-
|
|
|
160
|
-
|
|
|
161
|
-
|
|
|
162
|
-
|
|
|
163
|
-
|
|
|
164
|
-
|
|
165
|
-
The public loader is `lib/fiber_audit.rb`.
|
|
166
|
-
|
|
167
|
-
## 7. v0.1.0 Static Pipeline
|
|
168
|
-
|
|
169
|
-
The pipeline below is implemented and covered by unit, fixture, CLI, and golden
|
|
170
|
-
report tests.
|
|
171
|
-
|
|
172
|
-
```text
|
|
173
|
-
CLI / Project discovery
|
|
174
|
-
|
|
|
175
|
-
v
|
|
176
|
-
Configuration + source glob expansion
|
|
177
|
-
|
|
|
178
|
-
+----------------------+
|
|
179
|
-
| |
|
|
180
|
-
v v
|
|
181
|
-
Rubydex SemanticIndex Prism CallSiteExtractor
|
|
182
|
-
(project-wide meaning) (local syntax and calls)
|
|
183
|
-
| |
|
|
184
|
-
+----------+-----------+
|
|
185
|
-
|
|
|
186
|
-
v
|
|
187
|
-
ExecutionContextResolver
|
|
188
|
-
|
|
|
189
|
-
v
|
|
190
|
-
Enabled rules FA1001–FA1007
|
|
191
|
-
|
|
|
192
|
-
v
|
|
193
|
-
Findings
|
|
194
|
-
|
|
|
195
|
-
v
|
|
196
|
-
Inline/YAML Suppression Store
|
|
197
|
-
|
|
|
198
|
-
+--------+---------+
|
|
199
|
-
| |
|
|
200
|
-
v v
|
|
201
|
-
Active findings Suppressed findings
|
|
202
|
-
| |
|
|
203
|
-
+--------+---------+
|
|
204
|
-
|
|
|
205
|
-
v
|
|
206
|
-
Audit::Result
|
|
207
|
-
|
|
|
208
|
-
+--------+---------+
|
|
209
|
-
| |
|
|
210
|
-
v v
|
|
211
|
-
Text reporter JSON reporter
|
|
212
|
-
| |
|
|
213
|
-
+--------+---------+
|
|
214
|
-
|
|
|
215
|
-
v
|
|
216
|
-
Exit status
|
|
217
|
-
```
|
|
218
|
-
|
|
219
|
-
### Pipeline behavior
|
|
220
|
-
|
|
221
|
-
1. Detect the project root and configuration file.
|
|
222
|
-
2. Validate configuration before analysis starts.
|
|
223
|
-
3. Expand included Ruby files and remove excluded paths.
|
|
224
|
-
4. Build the Rubydex semantic index once for the workspace.
|
|
225
|
-
5. Parse each selected source file once with Prism.
|
|
226
|
-
6. Convert call nodes into FiberAudit-owned `CallSite` values.
|
|
227
|
-
7. Resolve receivers and execution contexts on a best-effort basis.
|
|
228
|
-
8. Run enabled rules over call sites.
|
|
229
|
-
9. Publish evidence-bearing findings to a collection.
|
|
230
|
-
10. Parse and apply inline and YAML suppressions.
|
|
231
|
-
11. Derive the project status from active findings.
|
|
232
|
-
12. Render the selected format and return the configured exit status.
|
|
233
|
-
|
|
234
|
-
## 8. Component Boundaries
|
|
235
|
-
|
|
236
|
-
### 8.1 CLI and project discovery
|
|
237
|
-
|
|
238
|
-
**Current files**
|
|
239
|
-
|
|
240
|
-
- `lib/fiber_audit/cli.rb`
|
|
241
|
-
- `lib/fiber_audit/project.rb`
|
|
242
|
-
|
|
243
|
-
Responsibilities:
|
|
244
|
-
|
|
245
|
-
- parse commands and flags;
|
|
246
|
-
- discover the project root;
|
|
247
|
-
- locate `.fiber-audit.yml` or honor `--config`;
|
|
248
|
-
- invoke `Audit`;
|
|
249
|
-
- select a reporter;
|
|
250
|
-
- map results and errors to process exit codes.
|
|
251
|
-
|
|
252
|
-
The CLI must not contain AST traversal, rule matching, or report assembly logic.
|
|
253
|
-
|
|
254
|
-
### 8.2 Configuration
|
|
16
|
+
| Configuration and suppressions | Strict static/runtime validation and post-analysis filtering | Implemented |
|
|
17
|
+
| Static adapters and rules | Rubydex/Prism extraction and FA1001–FA1007 | Implemented |
|
|
18
|
+
| Reporters | Deterministic text and static JSON schema 1.0 | Implemented |
|
|
19
|
+
| Runtime recorder and probes | Bounded JSONL 1.0 sessions and targeted operations | Implemented |
|
|
20
|
+
| Scheduler watchdog | Heartbeat stalls and bounded operation overlap | Implemented |
|
|
21
|
+
| Operation-liveness monitor | Independent bounded active-operation age evidence | Implemented |
|
|
22
|
+
| Shared operation semantics | Static/runtime semantic profiles and scalar classification | Implemented |
|
|
23
|
+
| Combined reporting | Correlated static/runtime finding presentation | Future work |
|
|
255
24
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
Recognized static configuration shape:
|
|
25
|
+
## Configuration boundary
|
|
259
26
|
|
|
260
27
|
```yaml
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
rules:
|
|
273
|
-
FA1001:
|
|
28
|
+
runtime:
|
|
29
|
+
redaction:
|
|
30
|
+
mode: strict
|
|
31
|
+
sampling:
|
|
32
|
+
rate: 0.1
|
|
33
|
+
overhead:
|
|
34
|
+
max_events_per_second: 100
|
|
35
|
+
max_events_per_session: 10000
|
|
36
|
+
max_record_bytes: 16384
|
|
37
|
+
max_session_bytes: 10485760
|
|
38
|
+
watchdog:
|
|
274
39
|
enabled: true
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
The configuration boundary owns defaults, type validation, allowed formats,
|
|
285
|
-
severity coercion, and rule overrides. Configuration failures must become a
|
|
286
|
-
FiberAudit configuration error so the CLI can consistently exit with code 2.
|
|
287
|
-
|
|
288
|
-
### 8.3 Semantic indexing
|
|
289
|
-
|
|
290
|
-
**Current file:** `lib/fiber_audit/static/semantic_index.rb`
|
|
291
|
-
|
|
292
|
-
Rubydex supplies project-wide information:
|
|
293
|
-
|
|
294
|
-
- declarations;
|
|
295
|
-
- constant resolution;
|
|
296
|
-
- ancestry and descendants;
|
|
297
|
-
- constant references;
|
|
298
|
-
- source locations.
|
|
299
|
-
|
|
300
|
-
`SemanticIndex` is the only component that should directly depend on
|
|
301
|
-
`Rubydex::Graph`. It normalizes workspace paths and coordinates and returns
|
|
302
|
-
FiberAudit-owned values:
|
|
303
|
-
|
|
304
|
-
- `Declaration`
|
|
305
|
-
- `Reference`
|
|
306
|
-
- `Constant`
|
|
307
|
-
- `RubydexGap`
|
|
308
|
-
|
|
309
|
-
Known adapter limitations are exposed as `RubydexGap` values and documented by
|
|
310
|
-
the Rubydex spike fixtures.
|
|
311
|
-
|
|
312
|
-
### 8.4 Syntax and call-site extraction
|
|
313
|
-
|
|
314
|
-
**Current files:**
|
|
315
|
-
|
|
316
|
-
- `lib/fiber_audit/static/call_site.rb`
|
|
317
|
-
- `lib/fiber_audit/static/call_site_extractor.rb`
|
|
318
|
-
|
|
319
|
-
Prism supplies syntax-level information that Rubydex does not reliably expose,
|
|
320
|
-
including method names, receiver source, arguments, lexical nesting, and
|
|
321
|
-
precise call-site locations.
|
|
322
|
-
|
|
323
|
-
The target `CallSite` contract contains:
|
|
324
|
-
|
|
325
|
-
```text
|
|
326
|
-
path, line, column
|
|
327
|
-
receiver_source, receiver_constant, method_name
|
|
328
|
-
arguments, enclosing_symbol, nesting
|
|
329
|
-
execution_context, resolution, confidence
|
|
330
|
-
```
|
|
331
|
-
|
|
332
|
-
The extractor parses each file once and performs conservative receiver
|
|
333
|
-
inference. The obsolete `SourceIndex` placeholder has been removed.
|
|
334
|
-
|
|
335
|
-
### 8.5 Execution-context resolution
|
|
336
|
-
|
|
337
|
-
**Current files:**
|
|
338
|
-
|
|
339
|
-
- `lib/fiber_audit/execution_context.rb`
|
|
340
|
-
- `lib/fiber_audit/static/execution_context_resolver.rb`
|
|
341
|
-
|
|
342
|
-
Supported contexts are planned as:
|
|
343
|
-
|
|
344
|
-
```text
|
|
345
|
-
request, middleware, callback, view, job, websocket,
|
|
346
|
-
boot, console, rake_task, test, unknown
|
|
40
|
+
heartbeat_interval_ms: 25
|
|
41
|
+
stall_threshold_ms: 100
|
|
42
|
+
max_frames: 20
|
|
43
|
+
operation_liveness:
|
|
44
|
+
enabled: true
|
|
45
|
+
poll_interval_ms: 100
|
|
46
|
+
long_active_threshold_ms: 1000
|
|
47
|
+
fail_open: true
|
|
347
48
|
```
|
|
348
49
|
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
1. semantic inheritance;
|
|
352
|
-
2. path-based fallback;
|
|
353
|
-
3. callback/DSL syntax hints;
|
|
354
|
-
4. `unknown`.
|
|
355
|
-
|
|
356
|
-
The resolver must never invent certainty. Unknown or heuristic contexts remain
|
|
357
|
-
explicit and can lower confidence.
|
|
358
|
-
|
|
359
|
-
### 8.6 Static rule system
|
|
50
|
+
Runtime policy, watchdog policy, and operation-liveness policy are immutable FiberAudit-owned values. CLI activation transports watchdog and liveness policy in separate, exact-key, size-bounded JSON environment values. Missing transport keeps programmatic boot inert; explicit CLI runtime activation transports the configured policies and enables probes.
|
|
360
51
|
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
Rules consume FiberAudit `CallSite` values and emit `Finding` values. They do
|
|
364
|
-
not parse files and do not access Rubydex directly.
|
|
365
|
-
|
|
366
|
-
Shipped v0.1.0 rules:
|
|
52
|
+
## Static rules
|
|
367
53
|
|
|
368
54
|
| ID | Concern | Default severity |
|
|
369
55
|
|---|---|---:|
|
|
370
|
-
| FA1001 |
|
|
371
|
-
| FA1002 |
|
|
372
|
-
| FA1003 |
|
|
373
|
-
| FA1004 | Thread-
|
|
374
|
-
| FA1005 |
|
|
375
|
-
| FA1006 |
|
|
376
|
-
| FA1007 |
|
|
377
|
-
|
|
378
|
-
A rule registry owns registration, enumeration, configuration enablement, and
|
|
379
|
-
metadata used by `list-rules` and `explain`.
|
|
380
|
-
|
|
381
|
-
### 8.7 Findings and fingerprints
|
|
56
|
+
| FA1001 | Subprocess lifecycle and process-wait cooperation | info/medium |
|
|
57
|
+
| FA1002 | Thread-wait scheduler coordination | low |
|
|
58
|
+
| FA1003 | Synchronization scheduler coordination | low/info |
|
|
59
|
+
| FA1004 | True Thread-variable access shared across Fibers | medium |
|
|
60
|
+
| FA1005 | `IO.select` scheduler capability requirement | medium |
|
|
61
|
+
| FA1006 | Socket allocation and constructor endpoint semantics | low |
|
|
62
|
+
| FA1007 | HTTP scheduler cooperation in request-like contexts | medium |
|
|
382
63
|
|
|
383
|
-
|
|
64
|
+
FA1004 uses advisory medium severity because API/context evidence does not prove request-sensitive leakage. It never publishes thread-variable keys or values. FA1006 resolves shared constructor profiles but preserves rule ID and operation strings, so existing fingerprints remain stable.
|
|
384
65
|
|
|
385
|
-
|
|
386
|
-
- `lib/fiber_audit/findings/evidence.rb`
|
|
387
|
-
- `lib/fiber_audit/findings/finding.rb`
|
|
388
|
-
- `lib/fiber_audit/findings/collection.rb`
|
|
389
|
-
- `lib/fiber_audit/findings/severity.rb`
|
|
390
|
-
- `lib/fiber_audit/findings/confidence.rb`
|
|
391
|
-
- `lib/fiber_audit/correlation/fingerprint.rb`
|
|
66
|
+
## Runtime architecture
|
|
392
67
|
|
|
393
|
-
|
|
68
|
+
Runtime instrumentation is activated only by the explicit runtime command:
|
|
394
69
|
|
|
395
70
|
```text
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
```text
|
|
408
|
-
rule identity and title
|
|
409
|
-
category
|
|
410
|
-
severity and confidence
|
|
411
|
-
location and enclosing symbol
|
|
412
|
-
resolved operation and execution context
|
|
413
|
-
message, evidence, and remediation
|
|
414
|
-
stable fingerprint
|
|
415
|
-
```
|
|
416
|
-
|
|
417
|
-
The fingerprint is SHA-256 over:
|
|
418
|
-
|
|
419
|
-
```text
|
|
420
|
-
rule_id : normalized_path : enclosing_symbol : operation
|
|
421
|
-
```
|
|
422
|
-
|
|
423
|
-
Line number is intentionally excluded so a finding remains stable when nearby
|
|
424
|
-
source lines move.
|
|
425
|
-
|
|
426
|
-
`Finding.new` currently permits empty evidence while a finding is assembled.
|
|
427
|
-
Publication through a collection is intended to require at least one evidence
|
|
428
|
-
entry. Constructor and publication paths must enforce the same final invariant.
|
|
429
|
-
|
|
430
|
-
### 8.8 Suppressions
|
|
431
|
-
|
|
432
|
-
**Current files:**
|
|
433
|
-
|
|
434
|
-
- `lib/fiber_audit/suppressions/parser.rb`
|
|
435
|
-
- `lib/fiber_audit/suppressions/store.rb`
|
|
436
|
-
|
|
437
|
-
Inline form:
|
|
438
|
-
|
|
439
|
-
```ruby
|
|
440
|
-
# fiber-audit:disable FA1001 -- executed only by an offline migration
|
|
441
|
-
Open3.capture3(command)
|
|
442
|
-
# fiber-audit:enable FA1001
|
|
71
|
+
CLI runtime command
|
|
72
|
+
-> strict Environment settings
|
|
73
|
+
-> conditional RUBYOPT boot
|
|
74
|
+
-> one Lifecycle per process
|
|
75
|
+
-> owner-only Recorder / JSONL 1.0 session
|
|
76
|
+
-> ActiveOperations registry
|
|
77
|
+
-> targeted probe registry
|
|
78
|
+
-> optional Rails integration
|
|
79
|
+
-> scheduler Watchdog
|
|
80
|
+
-> OperationLivenessMonitor
|
|
443
81
|
```
|
|
444
82
|
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
```yaml
|
|
448
|
-
suppressions:
|
|
449
|
-
- rule: FA1001
|
|
450
|
-
symbol: DataMigration#run
|
|
451
|
-
reason: Executed only by an offline task
|
|
452
|
-
```
|
|
453
|
-
|
|
454
|
-
Every suppression requires a reason. Inline directives must come from actual
|
|
455
|
-
Ruby comments; directive-looking text in strings, heredocs, or regular
|
|
456
|
-
expressions is not a directive. Both disable and enable matching must use
|
|
457
|
-
comment locations rather than unrestricted line scans.
|
|
458
|
-
|
|
459
|
-
### 8.9 Audit coordinator
|
|
460
|
-
|
|
461
|
-
**Current file:** `lib/fiber_audit/audit.rb`
|
|
83
|
+
Requiring `fiber_audit` or `fiber_audit/runtime/boot` without the activation marker starts no probes, fibers, threads, or file output. The top-level loader does not require Rails.
|
|
462
84
|
|
|
463
|
-
|
|
464
|
-
must contain enough information for all reporters:
|
|
85
|
+
### Targeted observations and shared semantics
|
|
465
86
|
|
|
466
|
-
-
|
|
467
|
-
- suppressed findings;
|
|
468
|
-
- parse/analysis errors;
|
|
469
|
-
- derived status;
|
|
470
|
-
- static-only disclaimer and coverage metadata.
|
|
87
|
+
Narrow idempotent prepend wrappers observe only canonical operations represented by FA1001–FA1007. `OperationSemantics` owns category, wait possibility, inventory-only status, and an optional relevant scheduler capability. Static rules and runtime classification consume the same immutable profiles.
|
|
471
88
|
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
**Current files:** `lib/fiber_audit/reporters/`
|
|
475
|
-
|
|
476
|
-
Reporters consume `Audit::Result`; they do not rerun analysis or apply
|
|
477
|
-
suppressions.
|
|
478
|
-
|
|
479
|
-
- Text output is optimized for humans and CI logs.
|
|
480
|
-
- JSON output is a versioned external contract.
|
|
481
|
-
- The planned initial JSON schema version is `1.0`.
|
|
482
|
-
|
|
483
|
-
`Finding#to_h_for_json` is currently an internal serialization helper. It does
|
|
484
|
-
not by itself constitute the complete versioned report schema.
|
|
485
|
-
|
|
486
|
-
## 9. Dependency Direction
|
|
487
|
-
|
|
488
|
-
The desired dependency direction is inward toward FiberAudit-owned contracts:
|
|
89
|
+
`SchedulerEvidenceClassifier` adds only Boolean/nil measurements:
|
|
489
90
|
|
|
490
91
|
```text
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
+--> Suppression Store
|
|
497
|
-
+--> Rule Registry
|
|
498
|
-
|
|
|
499
|
-
v
|
|
500
|
-
CallSite
|
|
501
|
-
^
|
|
502
|
-
|
|
|
503
|
-
Context Resolver / Extractor
|
|
504
|
-
^ ^
|
|
505
|
-
| |
|
|
506
|
-
SemanticIndex Prism syntax
|
|
507
|
-
|
|
|
508
|
-
Rubydex graph
|
|
509
|
-
|
|
510
|
-
Rules --------------------------> Finding
|
|
511
|
-
Suppressions / Reporters -------> Finding
|
|
512
|
-
Finding ------------------------> Fingerprint, Location, Evidence
|
|
92
|
+
operation_wait_possible
|
|
93
|
+
operation_inventory_only
|
|
94
|
+
operation_scheduler_capability_required
|
|
95
|
+
operation_scheduler_capability_supported
|
|
96
|
+
operation_scheduler_cooperation_available
|
|
513
97
|
```
|
|
514
98
|
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
- rules must not depend on Rubydex or Prism node classes;
|
|
518
|
-
- reporters must not depend on indexes or rules;
|
|
519
|
-
- suppressions must not mutate rule behavior;
|
|
520
|
-
- the top-level gem loader must not require Rails;
|
|
521
|
-
- v0.1.0 code must not depend on runtime instrumentation modules.
|
|
522
|
-
|
|
523
|
-
## 10. Status and Exit Contracts
|
|
99
|
+
No semantic category Symbol/String or nested classifier value enters JSONL 1.0. A true availability measurement means only that scheduler/Fiber evidence was compatible and, for an optional capability, the captured hook was supported. Required `block` and `kernel_sleep` capabilities are inferred from known scheduler presence rather than measured separately. This does not prove cooperation, progress, safety, or absence of scheduler harm.
|
|
524
100
|
|
|
525
|
-
|
|
101
|
+
Scheduler snapshots preserve actual `Fiber#blocking?` values. Capture failure produces an all-unknown snapshot; readers must preserve nil rather than coerce it to false. Snapshot and classifier fields are additive scalar measurements under the unchanged JSONL schema 1.0 envelope.
|
|
526
102
|
|
|
527
|
-
|
|
528
|
-
|---|---|
|
|
529
|
-
| `FAIL` | At least one active critical or high finding |
|
|
530
|
-
| `REVIEW` | Medium risk, or unresolved low/unknown-confidence risk requiring review |
|
|
531
|
-
| `PASS_WITH_WARNINGS` | Only low or informational findings |
|
|
532
|
-
| `NO_FINDINGS` | No active findings |
|
|
103
|
+
### Scheduler watchdog
|
|
533
104
|
|
|
534
|
-
|
|
105
|
+
A scheduler-owned heartbeat reports monotonic progress. The process-local watchdog detects exclusive threshold crossings and emits bounded control events: explicit disabled/absent/active/unsupported state, one stall start/completion pair, safe project-relative frames, and bounded active-operation overlap. Overlap proves only co-occurrence on one Thread. Native work retaining the GVL can prevent both the heartbeat and watchdog Thread from running, so absence of a stall is not certification.
|
|
535
106
|
|
|
536
|
-
|
|
107
|
+
### Operation-liveness monitor
|
|
537
108
|
|
|
538
|
-
|
|
109
|
+
The lifecycle-owned `OperationLivenessMonitor` is independent of watchdog state. It polls an atomic bounded `ActiveOperations::Snapshot` every 100 ms by default and starts evidence when age is strictly greater than the default 1-second threshold. At most ten new threshold crossings emit per poll; both registry and per-poll truncation remain explicit. Operations outside the bounded snapshot may be unobserved, so absence of long-active events is never a complete-coverage claim.
|
|
539
110
|
|
|
540
|
-
|
|
541
|
-
|---:|---|
|
|
542
|
-
| 0 | No active finding at or above the configured threshold |
|
|
543
|
-
| 1 | At least one active finding at or above the threshold |
|
|
544
|
-
| 2 | Configuration or analysis error |
|
|
545
|
-
| 3 | Reserved; not emitted in v0.1.0 |
|
|
111
|
+
Each observed crossing emits an unsampled-but-budgeted `operation_long_active_started/completed` pair. Registry disappearance closes with `operation_finished: true`; shutdown closes with false. The latter does not claim application failure. Long-active duration is not a scheduler stall, deadlock, or causal diagnosis. Active, disabled, and unsupported state events make monitor coverage explicit.
|
|
546
112
|
|
|
547
|
-
|
|
548
|
-
parse errors remain report data so analysis can continue on other files.
|
|
113
|
+
### Bounds, privacy, and lifecycle
|
|
549
114
|
|
|
550
|
-
|
|
115
|
+
Targeted operations register before ordinary event sampling so watchdog and liveness evidence can observe sampled-out work. Control evidence bypasses random sampling but remains subject to rate, event, record-size, and session-size limits. Drops, truncation, internal errors, unsupported state, and incomplete sessions remain visible.
|
|
551
116
|
|
|
552
|
-
|
|
117
|
+
Runtime values are allowlisted at capture time. Commands and arguments, URLs, addresses, hosts, ports, headers, bodies, payloads, return values, exception messages, environment secrets, and thread-variable keys/values are never retained. Only project-relative locations or explicit unknown/external sentinels are published.
|
|
553
118
|
|
|
554
|
-
|
|
555
|
-
continue with other files or references.
|
|
556
|
-
- **Invalid invocation or configuration:** raise a FiberAudit-owned error and
|
|
557
|
-
let the CLI return exit code 2.
|
|
119
|
+
Shutdown deactivates Rails integration and probes before stopping the liveness monitor, then deactivates scheduler observation/stops the watchdog, and closes the recorder last. This prevents new registrations while open liveness pairs are closed. Fork rebinding closes only the inherited writer, discards inherited observer references without touching their locks or Threads, resets Fiber context, and constructs a new process-local session and observers.
|
|
558
120
|
|
|
559
|
-
|
|
560
|
-
components should not need to rescue Rubydex-, Prism-, or YAML-specific errors.
|
|
121
|
+
A successful `exec` may intentionally leave a valid incomplete session without `session_end`. Every reader must validate records with `Runtime::JSONL::Schema` and separately enforce stream ordering/session consistency.
|
|
561
122
|
|
|
562
|
-
|
|
563
|
-
plan recommends a dedicated `lib/fiber_audit/errors.rb`.
|
|
123
|
+
### Verification and performance
|
|
564
124
|
|
|
565
|
-
|
|
125
|
+
`script/scheduler-semantics` behaviorally checks only capabilities consumed by FiberAudit: Process wait variants, coordination hooks, IO.select, localhost address resolution, storage semantics, scheduler replacement, and Ruby 4 IO-close interruption. Every case and the RSpec subprocess are bounded.
|
|
566
126
|
|
|
567
|
-
|
|
127
|
+
`benchmark/runtime_probe_overhead.rb` runs absent, installed/inactive, active sampling-zero, and active sampling-one scenarios in isolated subprocesses. It reports timing and recorder accounting for local diagnosis. There is no CI wall-clock threshold; optimization requires benchmark evidence.
|
|
568
128
|
|
|
569
|
-
|
|
129
|
+
Remaining runtime work is combined static/runtime correlation and any separately approved coverage contract that could support stronger status semantics.
|
|
570
130
|
|
|
571
|
-
|
|
572
|
-
context resolution, all built-in rules, configuration, suppressions, project
|
|
573
|
-
discovery, orchestration, reporters, CLI exit paths, and a versioned golden
|
|
574
|
-
report.
|
|
575
|
-
|
|
576
|
-
### v0.1.0 coverage
|
|
577
|
-
|
|
578
|
-
- exact `CallSite` extraction and receiver inference;
|
|
579
|
-
- execution-context classification;
|
|
580
|
-
- positive and negative fixtures for every rule;
|
|
581
|
-
- shadowed-constant negatives to avoid name-only false positives;
|
|
582
|
-
- stable fingerprints across repeated analysis;
|
|
583
|
-
- suppression behavior, including comment-only enable/disable directives;
|
|
584
|
-
- project-root and configuration discovery;
|
|
585
|
-
- text and JSON reporter contracts;
|
|
586
|
-
- golden JSON output;
|
|
587
|
-
- clean, findings, and invalid-config CLI exit paths.
|
|
588
|
-
|
|
589
|
-
Fixture applications should remain small and deterministic:
|
|
590
|
-
|
|
591
|
-
```text
|
|
592
|
-
spec/fixtures/apps/poro_clean
|
|
593
|
-
spec/fixtures/apps/rails_blockers
|
|
594
|
-
spec/fixtures/apps/rails_contexts
|
|
595
|
-
spec/fixtures/reports/rails_blockers_v0.1.json
|
|
596
|
-
```
|
|
597
|
-
|
|
598
|
-
CI is configured to run linting, specs, and gem packaging on Ruby 3.3 and 3.4.
|
|
599
|
-
The workflow configuration does not itself prove that remote CI has passed.
|
|
600
|
-
|
|
601
|
-
## 13. Runtime Architecture Beyond v0.1.0
|
|
602
|
-
|
|
603
|
-
The long-term architecture adds a runtime branch alongside static analysis:
|
|
131
|
+
## Repository map
|
|
604
132
|
|
|
605
133
|
```text
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
resource policy, injected clocks and sampling, bounded JSONL writing, explicit
|
|
624
|
-
drop accounting, and crash-tolerant session recording. The explicit `runtime`
|
|
625
|
-
command supervises a user-supplied command, injects a conditional Ruby boot,
|
|
626
|
-
forwards signals, preserves child status, and creates a distinct session for each
|
|
627
|
-
observed Ruby process.
|
|
628
|
-
|
|
629
|
-
Explicit runtime boot also installs a narrow observer for schedulers configured
|
|
630
|
-
through `Fiber.set_scheduler`. A scheduler-owned heartbeat fiber updates
|
|
631
|
-
monotonic progress; one process-local watchdog thread detects threshold crossings.
|
|
632
|
-
Each stall emits at most one start and one completion event plus a configured,
|
|
633
|
-
bounded set of project-relative frame events. An active-operation registry uses
|
|
634
|
-
only ephemeral thread/fiber identities and process-local sequences so targeted
|
|
635
|
-
operations can overlap scheduler stalls without retaining arguments or request
|
|
636
|
-
identifiers.
|
|
637
|
-
|
|
638
|
-
Watchdog state is explicit: disabled, absent, active, or unsupported. State and
|
|
639
|
-
stall events bypass random sampling but still consume all recorder rate, event,
|
|
640
|
-
record, and session limits. Runtime JSONL schema `1.0` and its `session_start`
|
|
641
|
-
contract remain unchanged; watchdog policy travels only in strict activation
|
|
642
|
-
settings, while state and policy measurements are ordinary bounded events.
|
|
643
|
-
Explicit boot installs narrow, idempotent `Module#prepend` wrappers for the
|
|
644
|
-
operations represented by FA1001–FA1007. One shared probe base owns monotonic
|
|
645
|
-
timing, sampled completion/abortion events, conservative direct project
|
|
646
|
-
callsites, recursion protection, and active-operation registration. Probe events
|
|
647
|
-
retain only canonical operations, duration, project-relative location,
|
|
648
|
-
ephemeral identities, operation sequence, and a small fixed set of Booleans.
|
|
649
|
-
Commands, URLs, addresses, ports, headers, payloads, return data, exception data,
|
|
650
|
-
and thread-local keys or values are never retained.
|
|
651
|
-
|
|
652
|
-
A process-local registry deactivates wrappers without attempting to remove Ruby
|
|
653
|
-
prepends. A narrow `Kernel#require` wrapper rescans only known standard-library
|
|
654
|
-
targets after successful loads; no unrestricted tracing, `load`, `const_missing`,
|
|
655
|
-
or autoload observation is used. Unknown ownership is skipped rather than mapped
|
|
656
|
-
to a project callsite.
|
|
657
|
-
|
|
658
|
-
Stage 5 adds `source: targeted_probe` and the event kinds `operation_started`,
|
|
659
|
-
`operation_completed`, and `operation_aborted`. These values use existing bounded
|
|
660
|
-
identifier fields and are backward-compatible additions to runtime JSONL schema
|
|
661
|
-
`1.0`; the envelope, payload keys, and original golden fixture remain unchanged.
|
|
662
|
-
|
|
663
|
-
Shutdown first deactivates probes, then makes scheduler callbacks inert, requests
|
|
664
|
-
heartbeat/watchdog stop, bounds and joins the watchdog thread, completes any open
|
|
665
|
-
stall, and only then closes the recorder. Fork rebinding discards inherited probe
|
|
666
|
-
and watchdog references before touching their locks and creates process-local
|
|
667
|
-
replacements.
|
|
668
|
-
|
|
669
|
-
Stage 6 adds Rails execution context detection. A bounded, PID-aware fiber-local
|
|
670
|
-
context stack tracks the current execution context during probe observations.
|
|
671
|
-
The fiber-local stack uses `Fiber.current` instance variables to avoid thread-local
|
|
672
|
-
key visibility, validates against `Context::ALL`, enforces `MAX_DEPTH = 32`, and
|
|
673
|
-
resets on fork. A process-local `RailsIntegration` class hooks into Rails boundaries
|
|
674
|
-
via `Module#prepend`: Rack middleware (`:middleware`), `ActionController::Metal#process_action`
|
|
675
|
-
(`:request`), `ActiveJob::Base#perform_now` (`:job`), and `ActionCable::Channel::Base#dispatch_action`
|
|
676
|
-
(`:websocket`). Wrappers consult the active integration before setting context and become
|
|
677
|
-
inert after deactivation or fork, preserving application semantics. The integration
|
|
678
|
-
supports late loading: hooks are installed when Rails components become available,
|
|
679
|
-
even after runtime boot. Probe observations snapshot the context once at start and
|
|
680
|
-
propagate it through active operations and events. Lifecycle wires context store and
|
|
681
|
-
Rails integration ownership, shutdown deactivates Rails integration before probes,
|
|
682
|
-
and fork rebinding resets context and rebuilds integration. JSONL schema 1.0 and
|
|
683
|
-
privacy requirements are preserved; no new schema fields are added.
|
|
684
|
-
|
|
685
|
-
Loading the gem normally performs no instrumentation, fibers, threads, or file
|
|
686
|
-
I/O. The observer is activated only by explicit runtime boot. A native operation
|
|
687
|
-
that retains Ruby's GVL can prevent the watchdog thread from running until the
|
|
688
|
-
operation returns; absence or unsupported monitoring and absence of stalls are
|
|
689
|
-
never clean certification.
|
|
690
|
-
|
|
691
|
-
Remaining runtime concepts include:
|
|
692
|
-
|
|
693
|
-
- static/runtime evidence merging;
|
|
694
|
-
- runtime coverage sufficient to support future `PASS` semantics.
|
|
695
|
-
|
|
696
|
-
Runtime components must continue to emit or enrich the common finding model
|
|
697
|
-
rather than establish a parallel reporting model.
|
|
698
|
-
|
|
699
|
-
## 14. Repository Map
|
|
700
|
-
|
|
701
|
-
```text
|
|
702
|
-
lib/fiber_audit.rb public loader
|
|
703
|
-
lib/fiber_audit/cli.rb command and exit-code boundary
|
|
704
|
-
lib/fiber_audit/project.rb root/config discovery
|
|
705
|
-
lib/fiber_audit/audit.rb static coordinator
|
|
706
|
-
lib/fiber_audit/configuration.rb validated static configuration
|
|
707
|
-
lib/fiber_audit/findings/ public result values
|
|
708
|
-
lib/fiber_audit/correlation/fingerprint.rb stable identity
|
|
709
|
-
lib/fiber_audit/suppressions/ suppression parsing and filtering
|
|
710
|
-
lib/fiber_audit/static/ semantic, call-site, context, rules
|
|
711
|
-
lib/fiber_audit/reporters/ text and JSON schema 1.0
|
|
712
|
-
lib/fiber_audit/runtime/ values, lifecycle, watchdog, probes
|
|
713
|
-
ARCHITECTURE.md supported architecture and boundaries
|
|
714
|
-
```
|
|
715
|
-
|
|
716
|
-
## 15. Maintaining This Document
|
|
717
|
-
|
|
718
|
-
Update this document when the supported architecture changes:
|
|
719
|
-
|
|
720
|
-
1. Describe components as implemented only when source and meaningful specs
|
|
721
|
-
exist.
|
|
722
|
-
2. Update diagrams when dependency direction changes.
|
|
723
|
-
3. Record external report-schema changes as versioned contract changes.
|
|
724
|
-
4. Keep future runtime architecture separate from current static behavior.
|
|
725
|
-
6. Never use the existence of a built gem artifact as evidence that a release or
|
|
726
|
-
architecture stage is complete.
|
|
134
|
+
bin/fiber-audit executable
|
|
135
|
+
lib/fiber_audit.rb public loader
|
|
136
|
+
lib/fiber_audit/cli.rb command and exit-code boundary
|
|
137
|
+
lib/fiber_audit/configuration.rb validated configuration
|
|
138
|
+
lib/fiber_audit/operation_semantics.rb shared operation profiles
|
|
139
|
+
lib/fiber_audit/static/ static extraction/context/rules
|
|
140
|
+
lib/fiber_audit/runtime/ runtime values, lifecycle, watchdog, probes
|
|
141
|
+
lib/fiber_audit/runtime/scheduler_evidence_classifier.rb scalar runtime interpretation
|
|
142
|
+
lib/fiber_audit/runtime/operation_liveness_policy.rb strict monitor policy
|
|
143
|
+
lib/fiber_audit/runtime/operation_liveness_monitor.rb bounded operation-age evidence
|
|
144
|
+
script/scheduler-semantics used-capability behavior contract
|
|
145
|
+
benchmark/runtime_probe_overhead.rb local measurement-only benchmark
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## Maintenance
|
|
149
|
+
|
|
150
|
+
Update this document when supported architecture changes. Describe features as implemented only after source and meaningful specs exist, record external schema changes as versioned contracts, and keep future work distinct from shipped behavior.
|