@lunora/advisor 1.0.0-alpha.9 → 1.0.0-alpha.90
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.
- package/LICENSE.md +6 -0
- package/README.md +60 -5
- package/dist/index.d.mts +4130 -1095
- package/dist/index.d.ts +4130 -1095
- package/dist/index.mjs +1 -87
- package/dist/packem_shared/MAP_VERSION-DEJGm0wI.mjs +1 -0
- package/dist/packem_shared/actionFetchSsrf-Z61P0o8U.mjs +1 -0
- package/dist/packem_shared/actionWithoutErrorHandling-4GCBT0_z.mjs +1 -0
- package/dist/packem_shared/adminRouteWithoutGuard-DPE7LuNh.mjs +1 -0
- package/dist/packem_shared/aiRawRunEscapeHatch-Dq43DVD9.mjs +1 -0
- package/dist/packem_shared/aiRunWithoutLogging-CvHHtEN9.mjs +1 -0
- package/dist/packem_shared/aiToolSideEffectPromptInjection-K42X3QzJ.mjs +1 -0
- package/dist/packem_shared/aiUnboundedGenerationPublic-C17h6sMV.mjs +1 -0
- package/dist/packem_shared/allowUnauthenticatedShardAccessEnabled-CjXI-kda.mjs +1 -0
- package/dist/packem_shared/argument-derived-sink-DLXFC79t.mjs +1 -0
- package/dist/packem_shared/authApiCallWithoutHeaders-C1OOWML5.mjs +1 -0
- package/dist/packem_shared/authCsrfCheckDisabled-Dz27bDzp.mjs +1 -0
- package/dist/packem_shared/authEmailVerificationDisabled-QTDD7TAU.mjs +1 -0
- package/dist/packem_shared/authScimWithoutTransactions-FqdTmUJs.mjs +1 -0
- package/dist/packem_shared/authSecureCookiesDisabled-CrGYulfJ.mjs +1 -0
- package/dist/packem_shared/authSessionFreshageZero-yWE6CGYP.mjs +1 -0
- package/dist/packem_shared/authTrustedOriginsWildcard-xpeRXfGF.mjs +1 -0
- package/dist/packem_shared/browserAllowPrivateTargets-Cj5sizhv.mjs +1 -0
- package/dist/packem_shared/browserUserUrlWithoutAllowlist-Wl3xHr7v.mjs +1 -0
- package/dist/packem_shared/circularFk-DtcWFJxK.mjs +1 -0
- package/dist/packem_shared/classifySensitivity-JnjaTGYi.mjs +1 -0
- package/dist/packem_shared/commitOrderedHardDelete-BPdwOKA7.mjs +1 -0
- package/dist/packem_shared/compareToBaseline-DBgN5YqX.mjs +1 -0
- package/dist/packem_shared/constraintValidator-DoRJD9Is.mjs +1 -0
- package/dist/packem_shared/containerInstanceKeyFromUserInput-uEQQVsEz.mjs +1 -0
- package/dist/packem_shared/containerOversizedInstance-Bx89uR7E.mjs +1 -0
- package/dist/packem_shared/containerPublicInternet-BFfZf_P4.mjs +1 -0
- package/dist/packem_shared/containerRuntimeEgressRelaxation-pkpyXNou.mjs +1 -0
- package/dist/packem_shared/containerStartEnableInternetOverride-BBY4PMG1.mjs +1 -0
- package/dist/packem_shared/dedupeCacheKeys-DtBOHffV.mjs +1 -0
- package/dist/packem_shared/duplicateIndex-Cip6-Rpu.mjs +1 -0
- package/dist/packem_shared/emptyIndex-BnHDcXza.mjs +1 -0
- package/dist/packem_shared/errorRateOutlier-pr3_ZKbq.mjs +1 -0
- package/dist/packem_shared/errorWithoutCatalog-BTfvaXHR.mjs +1 -0
- package/dist/packem_shared/exportSinkMisconfigured-JfbAx9AI.mjs +1 -0
- package/dist/packem_shared/externalSourceIncrementalNoDeletePath-BCzm3HzF.mjs +1 -0
- package/dist/packem_shared/externalSourceOnGlobal-CH7xbJ49.mjs +1 -0
- package/dist/packem_shared/externalSourceUnscoped-BxU2uSXk.mjs +1 -0
- package/dist/packem_shared/fanOutBreadth-CBtmZnoh.mjs +1 -0
- package/dist/packem_shared/filterOnPrimaryKey-COQRpmnu.mjs +1 -0
- package/dist/packem_shared/filterWithoutIndex-Cf-tXY_A.mjs +1 -0
- package/dist/packem_shared/finding-NrKO8idM.mjs +1 -0
- package/dist/packem_shared/fk-index-DXYS17cc.mjs +1 -0
- package/dist/packem_shared/flagGatesSecurityWithUnsafeDefault-i-Befg8b.mjs +1 -0
- package/dist/packem_shared/flagReadInSubscription-DabIhYGD.mjs +1 -0
- package/dist/packem_shared/fromServerSchema-D2nTknz0.mjs +1 -0
- package/dist/packem_shared/geoIndexFieldNotGeopoint-D0lOTm-_.mjs +1 -0
- package/dist/packem_shared/geoIndexUnused-D7C9Qr4U.mjs +1 -0
- package/dist/packem_shared/globalTableNearColumnLimit-BFbBBd6A.mjs +1 -0
- package/dist/packem_shared/gradeFromScore-KSt58rj1.mjs +1 -0
- package/dist/packem_shared/hardcodedSecret-Bw_4FYrs.mjs +1 -0
- package/dist/packem_shared/helpers-CwSEZdku.mjs +1 -0
- package/dist/packem_shared/hotShard-BwGYZ3Tq.mjs +1 -0
- package/dist/packem_shared/httpActionMissingAuthGuard-BS3JZgaz.mjs +1 -0
- package/dist/packem_shared/httpActionResponseHeaderInjection-DHnc8c9f.mjs +1 -0
- package/dist/packem_shared/hyperdriveOutsideAction-CPDdGP2g.mjs +1 -0
- package/dist/packem_shared/identityUndeclaredClaimTrusted-BDFqB7Dw.mjs +1 -0
- package/dist/packem_shared/imagesUrlSourceFromUserInput-DizsRh3M.mjs +1 -0
- package/dist/packem_shared/indexReferencesUnknownField-B_c3o9QR.mjs +1 -0
- package/dist/packem_shared/indexUtilization-CkVPZcVe.mjs +1 -0
- package/dist/packem_shared/insertManyUnsafeUserData-DWE8d_DF.mjs +1 -0
- package/dist/packem_shared/kvUnscopedUserKeyIdor-CIgMPzFj.mjs +1 -0
- package/dist/packem_shared/mailInboundDispatchWithoutVerify-CWwqXyPX.mjs +1 -0
- package/dist/packem_shared/mailRecipientFromRequestInput-SDCchLP7.mjs +1 -0
- package/dist/packem_shared/maskUncoveredPiiColumn-axEka4nd.mjs +1 -0
- package/dist/packem_shared/maskWeakHashStrategyOnPii-BC1n0F4-.mjs +1 -0
- package/dist/packem_shared/maskedRelationLeakViaWith-C8n-Mzb1.mjs +1 -0
- package/dist/packem_shared/mutatorFullRowReplace-BzRpZ47r.mjs +1 -0
- package/dist/packem_shared/nondeterministicQueryMutation-sxmixc0l.mjs +1 -0
- package/dist/packem_shared/normalizeIdUsedAsAuthorization-BXN-Can6.mjs +1 -0
- package/dist/packem_shared/notifyMissingPushConfig-DeQMoNwm.mjs +1 -0
- package/dist/packem_shared/notifySendOutsideAction-CU4T16cR.mjs +1 -0
- package/dist/packem_shared/outputProjectionMissingOnPublicRead-BZI8Y7am.mjs +1 -0
- package/dist/packem_shared/ownerFieldFromArgsNotAuth-CjOSUDKi.mjs +1 -0
- package/dist/packem_shared/paymentCreateWithoutAuthorize-CICGmRFR.mjs +1 -0
- package/dist/packem_shared/paymentWebhookWideTolerance-B-F5jOeA.mjs +1 -0
- package/dist/packem_shared/plaintextSecretInWranglerVariables-bNkqmNqV.mjs +1 -0
- package/dist/packem_shared/policyReferencesUnknownTable-CIKuRZ5Y.mjs +1 -0
- package/dist/packem_shared/privilegedDispatchUnvalidatedPayload-C6Qtc8aT.mjs +1 -0
- package/dist/packem_shared/privilegedFanoutFromPublicProcedure-Coqt23CQ.mjs +1 -0
- package/dist/packem_shared/procedure-protections-DRQotu9I.mjs +1 -0
- package/dist/packem_shared/procedureWithoutStructuredEvent-CZ_B23nM.mjs +1 -0
- package/dist/packem_shared/publicArgumentUsesAny-BDEvMA8Q.mjs +1 -0
- package/dist/packem_shared/publicMutationWithoutRatelimit-Dsd4cSPD.mjs +1 -0
- package/dist/packem_shared/publicTableRlsOptoutConfusion-Dz7lbKKe.mjs +1 -0
- package/dist/packem_shared/queueWithoutDlq-BvHz3Opg.mjs +1 -0
- package/dist/packem_shared/r2sqlOutsideAction-BdLiLOAX.mjs +1 -0
- package/dist/packem_shared/ratelimitDefaultMemoryStore-Dj0Kk7t9.mjs +1 -0
- package/dist/packem_shared/ratelimitKeySpoofableOrGlobal-BzDzxnXm.mjs +1 -0
- package/dist/packem_shared/ratelimitMiddlewareFailOpen-iDJq68qx.mjs +1 -0
- package/dist/packem_shared/relationReferencesUnknownField-D8Qyth_P.mjs +1 -0
- package/dist/packem_shared/relationReferencesUnknownTable-CP4aWtAJ.mjs +1 -0
- package/dist/packem_shared/rlsUncoveredTable-CZ4ie4gX.mjs +1 -0
- package/dist/packem_shared/shapeTargetsGlobalTable-Bu3eEDic.mjs +1 -0
- package/dist/packem_shared/shapeUnknownTable-CREfNnWi.mjs +1 -0
- package/dist/packem_shared/signupMutationWithoutDisposableGating-BIsSLyhJ.mjs +1 -0
- package/dist/packem_shared/softDeleteIncludeDeletedFromArgs-C7Ugg4zb.mjs +1 -0
- package/dist/packem_shared/sqlInjectionRisk-CslaRBxz.mjs +1 -0
- package/dist/packem_shared/storageGenerateUploadUrlNoContentTypePin-CTIU_7Fj.mjs +1 -0
- package/dist/packem_shared/storageKeyFromUserArgs-C-QUcdJ3.mjs +1 -0
- package/dist/packem_shared/storagePresignedUrlForPrivateContent-yeu1s81k.mjs +1 -0
- package/dist/packem_shared/storageUploadWithoutContentTypeAllowlist-KSRG81Iu.mjs +1 -0
- package/dist/packem_shared/storageUploadWithoutMaxSize-BTiM9Q3A.mjs +1 -0
- package/dist/packem_shared/tableWithoutInsert-DQ-GxjFF.mjs +1 -0
- package/dist/packem_shared/ttlFieldNotTimestamp-E14I83wY.mjs +1 -0
- package/dist/packem_shared/unboundedStringArgument-DzbFJc5q.mjs +1 -0
- package/dist/packem_shared/unindexedForeignKey-Dypgn8uH.mjs +1 -0
- package/dist/packem_shared/unindexedRelationTarget-CSqRJWYZ.mjs +1 -0
- package/dist/packem_shared/unrestrictedWhereBranch-CcIBmHik.mjs +1 -0
- package/dist/packem_shared/userCreatingMutationWithoutCaptcha-B7l-S-rV.mjs +1 -0
- package/dist/packem_shared/vectorsNamespaceFromUserInput-CDSOrkyX.mjs +1 -0
- package/dist/packem_shared/workflowDuplicateStepName-BU4rg5So.mjs +1 -0
- package/dist/packem_shared/workflowUnknownTarget-B8H7jwnH.mjs +1 -0
- package/dist/packem_shared/workflowUnused-BUSOPdHq.mjs +1 -0
- package/package.json +3 -2
- package/dist/packem_shared/AE_METRIC_EVENTS-DexctYv6.mjs +0 -85
- package/dist/packem_shared/adminRouteWithoutGuard-UUGBkAjU.mjs +0 -33
- package/dist/packem_shared/authApiCallWithoutHeaders-BeJhCZaf.mjs +0 -38
- package/dist/packem_shared/circularFk-B2freHrP.mjs +0 -84
- package/dist/packem_shared/constraintValidator-Dr9Py3FD.mjs +0 -186
- package/dist/packem_shared/containerOversizedInstance-5U1VKPRM.mjs +0 -36
- package/dist/packem_shared/containerPublicInternet-CuNerJE5.mjs +0 -30
- package/dist/packem_shared/duplicateIndex-BOublMSt.mjs +0 -57
- package/dist/packem_shared/emptyIndex-BX8EuEY7.mjs +0 -32
- package/dist/packem_shared/filterWithoutIndex-BYVeJaSs.mjs +0 -31
- package/dist/packem_shared/finding-Dm_zvzS1.mjs +0 -16
- package/dist/packem_shared/fk-index-IUK1ukgs.mjs +0 -7
- package/dist/packem_shared/fromServerSchema-TWb7dTHC.mjs +0 -51
- package/dist/packem_shared/hardcodedSecret-W2pz1UZB.mjs +0 -35
- package/dist/packem_shared/helpers-DNCkMWZQ.mjs +0 -4
- package/dist/packem_shared/hotShard-Ir5D0B6J.mjs +0 -48
- package/dist/packem_shared/hyperdriveOutsideAction-BgZqX7Xg.mjs +0 -30
- package/dist/packem_shared/indexReferencesUnknownField-DH0_dbUY.mjs +0 -36
- package/dist/packem_shared/indexUtilization-B5DMQ3bI.mjs +0 -45
- package/dist/packem_shared/maskUncoveredPiiColumn-DjGIPG6M.mjs +0 -61
- package/dist/packem_shared/mutatorFullRowReplace-BJnNDaIV.mjs +0 -26
- package/dist/packem_shared/nondeterministicQueryMutation-GXES1fLp.mjs +0 -35
- package/dist/packem_shared/policyReferencesUnknownTable-DtaIEovd.mjs +0 -38
- package/dist/packem_shared/publicArgumentUsesAny-C71b2NCf.mjs +0 -32
- package/dist/packem_shared/publicMutationWithoutRatelimit-xBpJ6GWK.mjs +0 -36
- package/dist/packem_shared/r2sqlOutsideAction-CtqxvMuV.mjs +0 -30
- package/dist/packem_shared/relationReferencesUnknownField-YznyXt_7.mjs +0 -54
- package/dist/packem_shared/relationReferencesUnknownTable-DrorpKYe.mjs +0 -33
- package/dist/packem_shared/rlsUncoveredTable-CxEfZ5eZ.mjs +0 -56
- package/dist/packem_shared/shapeTargetsGlobalTable-DHrf4Koi.mjs +0 -34
- package/dist/packem_shared/shapeUnknownTable-C8aDWFoe.mjs +0 -34
- package/dist/packem_shared/sqlInjectionRisk-zwytYGLt.mjs +0 -26
- package/dist/packem_shared/tableWithoutInsert-CbbaYIP4.mjs +0 -34
- package/dist/packem_shared/unboundedStringArgument-DThg2-wt.mjs +0 -32
- package/dist/packem_shared/unindexedForeignKey-BgJbKyqK.mjs +0 -45
- package/dist/packem_shared/unindexedRelationTarget-D6eyj6Xx.mjs +0 -53
- package/dist/packem_shared/userCreatingMutationWithoutCaptcha-CH31YsUZ.mjs +0 -42
- package/dist/packem_shared/workflowDuplicateStepName-ioBxPBCy.mjs +0 -48
- package/dist/packem_shared/workflowUnknownTarget-Cdd7WhKQ.mjs +0 -34
- package/dist/packem_shared/workflowUnused-D0jHxdz9.mjs +0 -38
package/LICENSE.md
CHANGED
|
@@ -103,3 +103,9 @@ Unless required by applicable law or agreed to in writing, software distributed
|
|
|
103
103
|
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
|
104
104
|
CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
|
105
105
|
specific language governing permissions and limitations under the License.
|
|
106
|
+
|
|
107
|
+
<!-- DEPENDENCIES -->
|
|
108
|
+
<!-- /DEPENDENCIES -->
|
|
109
|
+
|
|
110
|
+
<!-- TYPE_DEPENDENCIES -->
|
|
111
|
+
<!-- /TYPE_DEPENDENCIES -->
|
package/README.md
CHANGED
|
@@ -79,20 +79,75 @@ for (const finding of findings) {
|
|
|
79
79
|
|
|
80
80
|
### Runtime lints
|
|
81
81
|
|
|
82
|
-
The runtime tier (`hot_shard`, `index_utilization`, `constraint_validator`) reads observed signal off the `LintContext` (`shardTraffic`, `tableScans`, `indexHits`, `tableSamples`). The Studio backend fills those from each shard's durable counters
|
|
82
|
+
The runtime tier (`hot_shard`, `index_utilization`, `constraint_validator`) reads observed signal off the `LintContext` (`shardTraffic`, `tableScans`, `indexHits`, `tableSamples`). The Studio backend fills those from each shard's durable counters:
|
|
83
83
|
|
|
84
84
|
```ts
|
|
85
|
-
import { fromServerSchema,
|
|
85
|
+
import { fromServerSchema, runAdvisor } from "@lunora/advisor";
|
|
86
86
|
|
|
87
87
|
import schema from "./lunora/schema";
|
|
88
88
|
|
|
89
|
-
// `
|
|
90
|
-
|
|
91
|
-
const findings = runAdvisor({ schema: fromServerSchema(schema),
|
|
89
|
+
// `shardTraffic` / `tableScans` / `indexHits` / `tableSamples` come from wherever
|
|
90
|
+
// you read your shards' durable counters — the Studio backend reads its own.
|
|
91
|
+
const findings = runAdvisor({ schema: fromServerSchema(schema), shardTraffic, tableScans, indexHits, tableSamples }, { source: "runtime" });
|
|
92
92
|
```
|
|
93
93
|
|
|
94
|
+
An Analytics-Engine-backed alternative feeder (querying AE SQL for `lunora.index.hit`/`lunora.shard.request`/`lunora.table.scan` events instead of the in-DO counters) was quarantined off the package root: nothing in the runtime ever writes those AE events, so `shardTraffic` and `tableScans` always came back empty. `indexHits` came back empty too, unless the caller passed `declaredIndexes` — then it listed every declared index with `reads: 0`, a real zero-reads fact rather than a stand-in for "no data". The `AnalyticsMetricsOptions` / `AnalyticsMetricsSource` / `AnalyticsRuntimeMetrics` types it would have produced are still exported from `@lunora/advisor` — they describe the still-valid, still-optional shape of `runAdvisor`'s runtime input — but the loader function itself is not, until something actually emits those events.
|
|
95
|
+
|
|
94
96
|
A missing metric degrades to an empty array rather than throwing, so a partially configured read path still returns what it can.
|
|
95
97
|
|
|
98
|
+
### Observability map (score, coverage, baseline)
|
|
99
|
+
|
|
100
|
+
`runAdvisor` answers "what is wrong?". `scoreAdvisor` answers "how are we doing, and did it get worse?" — a scored coverage map over your procedures. It is a pure function over findings you already have, so it never re-runs a lint:
|
|
101
|
+
|
|
102
|
+
```ts
|
|
103
|
+
import { fromServerSchema, runAdvisor, scoreAdvisor } from "@lunora/advisor";
|
|
104
|
+
|
|
105
|
+
import schema from "./lunora/schema";
|
|
106
|
+
|
|
107
|
+
const context = { schema: fromServerSchema(schema) };
|
|
108
|
+
const findings = runAdvisor(context, { source: "static" });
|
|
109
|
+
const map = scoreAdvisor(context.procedureProtections ?? [], findings);
|
|
110
|
+
|
|
111
|
+
console.log(map.score, map.grade); // e.g. 84 "good"
|
|
112
|
+
console.log(map.summary); // { clean: 9, exempt: 0, failing: 1, procedures: 12, rulesFired: 6, warned: 2 }
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Each procedure starts at 100 and loses each fired **rule's** weight (`Lint.weight`, else a severity ladder: `ERROR` 20 / `WARN` 10 / `INFO` 5) — charged once however many times that rule fires — then rolls up into a weighted global mean: public handlers count double, internal ones and queries half. Findings that name no procedure (schema shape, wrangler config) land in a project bucket weighted against the procedure population, so schema debt genuinely moves the grade.
|
|
116
|
+
|
|
117
|
+
The verdicts are `clean` / `warned` / `failing` / `exempt` — named for severity, because the score is driven by every lint family rather than an observability family.
|
|
118
|
+
|
|
119
|
+
Commit the map and gate CI on it:
|
|
120
|
+
|
|
121
|
+
```ts
|
|
122
|
+
import { compareToBaseline, parseAdvisorMap } from "@lunora/advisor";
|
|
123
|
+
|
|
124
|
+
const baseline = parseAdvisorMap(JSON.parse(await readFile("lunora.advisor.map.json", "utf8")));
|
|
125
|
+
|
|
126
|
+
if (baseline === undefined) {
|
|
127
|
+
// Missing, hand-edited, or written by an older MAP_VERSION. Fail loudly —
|
|
128
|
+
// treating it as "no regression" would silently disable the gate forever.
|
|
129
|
+
throw new Error("advisor baseline is unreadable; regenerate lunora.advisor.map.json");
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const diff = compareToBaseline(map, baseline);
|
|
133
|
+
|
|
134
|
+
// `comparable` must be narrowed before `regressed` is reachable, so a stale
|
|
135
|
+
// baseline cannot read as a clean run.
|
|
136
|
+
if (!diff.comparable) {
|
|
137
|
+
throw new Error(`advisor baseline not comparable: ${diff.reason}`);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Five independent signals: the global score fell, an existing procedure got
|
|
141
|
+
// worse, one started failing, one's findings grew without its score moving, or
|
|
142
|
+
// the project bucket gained findings. The growth signals matter because a rule is
|
|
143
|
+
// charged once however many times it fires, and the project score saturates at 0.
|
|
144
|
+
if (diff.regressed) {
|
|
145
|
+
process.exitCode = 1;
|
|
146
|
+
}
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
`@lunora/codegen` exposes `toAdvisorContext()` to build the context straight from the feeder, and `lunora advisor` wraps all of this as a command. Full reference for the scoring, verdicts, and the baseline gate is in the [package docs](https://lunora.sh/docs/packages/advisor).
|
|
150
|
+
|
|
96
151
|
> This README covers the basics. For the full API, options, and guides, see the **[documentation](https://lunora.sh/docs/addons/studio)**.
|
|
97
152
|
|
|
98
153
|
## Related
|