@pikku/inspector 0.12.106 → 0.12.108
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/dist/add/add-auth.d.ts +1 -9
- package/dist/add/add-auth.js +64 -17
- package/dist/add/add-cli.js +4 -0
- package/dist/add/add-functions.js +27 -31
- package/dist/add/add-keyed-wiring.js +22 -2
- package/dist/add/add-middleware.js +17 -16
- package/dist/add/add-permission.d.ts +0 -3
- package/dist/add/add-permission.js +213 -22
- package/dist/add/add-scope.d.ts +1 -7
- package/dist/add/add-scope.js +1 -21
- package/dist/add/check-indirect-registrations.d.ts +9 -0
- package/dist/add/check-indirect-registrations.js +114 -0
- package/dist/error-codes.d.ts +1 -0
- package/dist/error-codes.js +1 -0
- package/dist/finalize.d.ts +10 -0
- package/dist/finalize.js +102 -0
- package/dist/index.d.ts +8 -6
- package/dist/index.js +6 -5
- package/dist/initial-state.d.ts +7 -0
- package/dist/initial-state.js +216 -0
- package/dist/inspector.d.ts +6 -4
- package/dist/inspector.js +28 -302
- package/dist/lite.d.ts +26 -0
- package/dist/lite.js +25 -0
- package/dist/source-file-cache.d.ts +11 -0
- package/dist/source-file-cache.js +34 -10
- package/dist/types-map.js +2 -1
- package/dist/types.d.ts +32 -0
- package/dist/utils/apply-declared-scopes.d.ts +8 -0
- package/dist/utils/apply-declared-scopes.js +21 -0
- package/dist/utils/canonical-type-string.d.ts +14 -0
- package/dist/utils/canonical-type-string.js +162 -0
- package/dist/utils/context-based-id.d.ts +7 -0
- package/dist/utils/context-based-id.js +9 -0
- package/dist/utils/custom-types-generator.d.ts +15 -1
- package/dist/utils/custom-types-generator.js +17 -5
- package/dist/utils/ensure-function-metadata.d.ts +0 -14
- package/dist/utils/ensure-function-metadata.js +4 -1
- package/dist/utils/extract-function-name.d.ts +1 -1
- package/dist/utils/extract-function-name.js +1 -3
- package/dist/utils/filter-inspector-state.js +31 -1
- package/dist/utils/get-property-value.d.ts +5 -0
- package/dist/utils/get-property-value.js +14 -0
- package/dist/utils/inspector-constants.d.ts +16 -0
- package/dist/utils/inspector-constants.js +16 -0
- package/dist/utils/post-process.d.ts +1 -2
- package/dist/utils/post-process.js +27 -27
- package/dist/utils/read-jsx-literal-text.js +31 -1
- package/dist/utils/resolve-callee-name.d.ts +27 -0
- package/dist/utils/resolve-callee-name.js +147 -0
- package/dist/utils/resolve-service-types.d.ts +8 -0
- package/dist/utils/resolve-service-types.js +21 -0
- package/dist/utils/schema-generator.js +29 -2
- package/dist/utils/serialize-inspector-state.d.ts +7 -1
- package/dist/utils/serialize-inspector-state.js +16 -1
- package/dist/utils/workflow/dsl/patterns.d.ts +1 -8
- package/dist/utils/workflow/dsl/patterns.js +1 -7
- package/dist/visit.js +2 -0
- package/package.json +25 -9
- package/CHANGELOG.md +0 -4368
- package/OPTIMIZATION-PLAN.md +0 -201
- package/knowledge/decisions/a-channel-with-auth-false-marks-its-connect-and-disconnect-sessionless.md +0 -22
- package/knowledge/decisions/a-declared-scope-id-never-shadows-a-definition.md +0 -20
- package/knowledge/decisions/a-dsl-step-virtual-user-is-the-literal-name-in-its-options.md +0 -27
- package/knowledge/decisions/a-feature-flags-anyof-is-read-from-the-ast-and-an-empty-list-is-refused.md +0 -20
- package/knowledge/decisions/a-non-literal-string-array-reads-as-absent.md +0 -25
- package/knowledge/decisions/a-permission-with-an-underscore-data-parameter-takes-no-data.md +0 -20
- package/knowledge/decisions/a-provider-login-virtual-user-is-never-runnable.md +0 -27
- package/knowledge/decisions/a-remote-addon-bound-credential-or-secret-must-be-wired.md +0 -27
- package/knowledge/decisions/a-route-auth-overrides-its-groups-auth.md +0 -22
- package/knowledge/decisions/a-route-requires-a-session-when-any-auth-signal-says-so.md +0 -29
- package/knowledge/decisions/a-webhook-source-with-verify-gets-a-singleton-secret-credential.md +0 -21
- package/knowledge/decisions/a-wire-with-auth-disabled-cannot-point-at-a-pikkufunc.md +0 -21
- package/knowledge/decisions/addon-contracts-cannot-wire-or-declare-handlers.md +0 -25
- package/knowledge/decisions/addon-declarations-name-the-secrets-and-credentials-the-app-lends-it.md +0 -19
- package/knowledge/decisions/an-inline-wiring-function-is-sessionless-unless-built-with-pikkufunc.md +0 -23
- package/knowledge/decisions/better-auth-admin-plugin-is-refused.md +0 -24
- package/knowledge/decisions/define-screens-scopes-must-be-string-literals.md +0 -18
- package/knowledge/decisions/index.md +0 -38
- package/knowledge/decisions/inspector-records-a-non-literal-global-grant-as-source-text.md +0 -20
- package/knowledge/decisions/only-one-pikku-better-auth-export-per-codebase.md +0 -19
- package/knowledge/decisions/scope-references-and-secret-aliases-are-critical-diagnostics.md +0 -23
- package/knowledge/decisions/scope-segments-may-not-be-wildcards-or-contain-colons.md +0 -23
- package/knowledge/decisions/shorthand-permission-entries-are-extracted.md +0 -22
- package/knowledge/decisions/system-roles-declare-literal-unqualified-scopes.md +0 -28
- package/knowledge/decisions/the-inspector-records-agent-permissions-only-to-aggregate-services.md +0 -14
- package/knowledge/decisions/vault-secrets-reach-no-sink-and-pii-stays-out-of-logs-and-webhooks.md +0 -30
- package/knowledge/decisions/webhook-gateway-wrappers-are-sessionless-and-gateway-auth-runs-inside-the-handler.md +0 -26
- package/knowledge/index.md +0 -14
- package/knowledge/questions/does-a-non-literal-remote-addon-auth-get-checked.md +0 -26
- package/knowledge/questions/index.md +0 -16
- package/knowledge/questions/is-an-incomplete-oauth2-block-dropped-without-a-log.md +0 -23
- package/knowledge/questions/should-app-functions-named-like-scenario-instrumentation-be-refused.md +0 -28
- package/knowledge/questions/should-the-openapi-document-default-every-operation-to-a-bearer-or-api-key.md +0 -22
- package/run-tests.sh +0 -68
- package/src/utils/test-data/inspector-state.json +0 -1687
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
type: overview
|
|
3
|
-
title: Decisions
|
|
4
|
-
description: Rules chosen in inspector, and what each one rules out
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# Decisions
|
|
8
|
-
|
|
9
|
-
A rule that was chosen, and what it rules out.
|
|
10
|
-
|
|
11
|
-
<!-- pikku:knowledge-index -->
|
|
12
|
-
- [A channel with auth false marks its connect and disconnect handlers sessionless](a-channel-with-auth-false-marks-its-connect-and-disconnect-sessionless.md) — The inspector synthesises metadata for a channel's connect and disconnect functions and sets sessionless from the channel's auth
|
|
13
|
-
- [A declared scope id never shadows a definition](a-declared-scope-id-never-shadows-a-definition.md) — A bare declareScopes id is added only when no definition already holds it, so an addon's richer scope tree is kept
|
|
14
|
-
- [A workflow DSL step's virtual user is the literal name written in its options object](a-dsl-step-virtual-user-is-the-literal-name-in-its-options.md) — The DSL extractor reads a step's virtual user from a property access or string-keyed element access in the options literal, and leaves it undefined when the value is not static
|
|
15
|
-
- [A feature flag's anyOf is read from the AST, and an empty anyOf is refused](a-feature-flags-anyof-is-read-from-the-ast-and-an-empty-list-is-refused.md) — add-feature-flag reads the scope names in anyOf statically, refuses a non-array or empty anyOf, and refuses a flag name containing the scope separator
|
|
16
|
-
- [A string array with one computed entry reads as absent, not as its literal entries](a-non-literal-string-array-reads-as-absent.md) — stringArrayProperty returns undefined unless every element of the array is a string literal
|
|
17
|
-
- [A permission whose data parameter starts with an underscore takes no data](a-permission-with-an-underscore-data-parameter-takes-no-data.md) — An underscore-prefixed data parameter marks a permission as auth-only, and pikkuAuth always has no data
|
|
18
|
-
- [A provider-login virtual user is never runnable, even when declared runnable](a-provider-login-virtual-user-is-never-runnable.md) — Runnable is derived from the account, so a virtual user with a provider login cannot be driven, and an explicit runnable true does not change that
|
|
19
|
-
- [A remote addon's bound credential or secret id must name a wired slot, or validation reports a critical error](a-remote-addon-bound-credential-or-secret-must-be-wired.md) — validateRemoteAddonAuth checks that a literal auth.credentialId or auth.secretId on a wireRemoteAddon names a declared credential or secret, and runs in every inspector pass
|
|
20
|
-
- [A route's own auth overrides its group's, and auth false on a route makes an inline function sessionless](a-route-auth-overrides-its-groups-auth.md) — The route's auth is used when it is true or false, the group's inherited value otherwise; a resolved false sets sessionless on an inline function
|
|
21
|
-
- [A route requires a session when any auth signal says so](a-route-requires-a-session-when-any-auth-signal-says-so.md) — Four places can demand a session for an HTTP route and they combine with OR; a scope gate counts as a session demand
|
|
22
|
-
- [A webhook source with a verify step declares a singleton credential for its secret](a-webhook-source-with-verify-gets-a-singleton-secret-credential.md) — When a webhook source has a verify step, the inspector registers a string credential named by the source unless the author sets credential
|
|
23
|
-
- [A wire with auth disabled cannot point at a pikkuFunc](a-wire-with-auth-disabled-cannot-point-at-a-pikkufunc.md) — A route or wiring with auth false that names a session-requiring pikkuFunc is reported as critical, and the function is not accepted
|
|
24
|
-
- [Addons may not call wiring helpers or declare middleware or permissions](addon-contracts-cannot-wire-or-declare-handlers.md) — Addon packages are banned from transport wirings, and their define* contracts may not carry middleware or permissions
|
|
25
|
-
- [An addon declaration names the secrets and credentials the app lends it](addon-declarations-name-the-secrets-and-credentials-the-app-lends-it.md) — secretGrants and credentialGrants are declared on the addon instance as lists of names the addon reads
|
|
26
|
-
- [An inline wiring function is sessionless unless its helper is pikkuFunc](an-inline-wiring-function-is-sessionless-unless-built-with-pikkufunc.md) — The inspector derives sessionless for a function inlined into a wiring from the name of the helper that built it
|
|
27
|
-
- [better-auth's admin plugin is refused in favour of pikkuBan](better-auth-admin-plugin-is-refused.md) — Wiring admin() in pikkuBetterAuth throws at build time, and the error names pikkuBan() as the replacement
|
|
28
|
-
- [A define-screens scopes list must be string literals, or the build reports a critical error](define-screens-scopes-must-be-string-literals.md) — add-define-screens reads each screen's scopes by AST and reports ADDON_SCREENS_NOT_STATIC when the value is not an array of string literals
|
|
29
|
-
- [A non-literal global grant is recorded as its source text, not dropped](inspector-records-a-non-literal-global-grant-as-source-text.md) — globalSecrets and globalCredentials on a wireAddon keep a computed value as the expression's source text
|
|
30
|
-
- [Only one pikkuBetterAuth export is allowed per codebase](only-one-pikku-better-auth-export-per-codebase.md) — pikkuBetterAuth must be an exported const, and a second definition is refused with the first file named
|
|
31
|
-
- [An undeclared scope and a secret service passed under another name are critical diagnostics](scope-references-and-secret-aliases-are-critical-diagnostics.md) — Post-processing reports a function that requires an undeclared scope, and a function-facing service that is a SecretService under another name
|
|
32
|
-
- [Scope segments may not be wildcards or contain colons](scope-segments-may-not-be-wildcards-or-contain-colons.md) — The inspector refuses an empty scope segment, a segment containing the separator, and a literal wildcard segment
|
|
33
|
-
- [Shorthand permission entries are extracted, so the audit never reads a guarded function as open](shorthand-permission-entries-are-extracted.md) — extractPermissionPikkuNames reads { canAdminOrg } shorthand entries in a permissions record as names, as the runtime does
|
|
34
|
-
- [System roles must declare literal, unqualified scopes](system-roles-declare-literal-unqualified-scopes.md) — A system role needs a literal scopes array of string literals, and its name may not contain the scope separator
|
|
35
|
-
- [The inspector records an agent's permissions only to aggregate the services they need, never to check access](the-inspector-records-agent-permissions-only-to-aggregate-services.md) — addAgent adds the agent's permission names to usedPermissions, and post-process reads that set only to collect each permission's services
|
|
36
|
-
- [Vault secrets reach no sink, and PII is kept out of logs, the console and webhooks only](vault-secrets-reach-no-sink-and-pii-stays-out-of-logs-and-webhooks.md) — check-classified-sinks rejects revealed secrets in every listed sink and PII only in the logger, console and webhook sinks
|
|
37
|
-
- [Webhook gateway wrappers are registered sessionless, and gateway auth is enforced inside the handler call](webhook-gateway-wrappers-are-sessionless-and-gateway-auth-runs-inside-the-handler.md) — The inspector and the runtime both register a webhook gateway's POST and verify routes as sessionless with auth false, so the route never demands a session and the gateway's own auth flag is applied only when the handler runs
|
|
38
|
-
<!-- /pikku:knowledge-index -->
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
type: decision
|
|
3
|
-
title: A non-literal global grant is recorded as its source text, not dropped
|
|
4
|
-
description: globalSecrets and globalCredentials on a wireAddon keep a computed value as the expression's source text
|
|
5
|
-
tags: [inspector, addons, grants]
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
# A non-literal global grant is recorded as its source text, not dropped
|
|
9
|
-
|
|
10
|
-
In `packages/inspector/src/add/add-wire-addon.ts`, the `globalSecrets` and
|
|
11
|
-
`globalCredentials` properties of a `wireAddon` call are read in the same loop as the
|
|
12
|
-
other options (lines 216-225). A string literal is stored as its text. Any other
|
|
13
|
-
expression is stored as `prop.initializer.getText()` (lines 219-221 and 223-225).
|
|
14
|
-
|
|
15
|
-
The comment at lines 217-218 gives the reason: "The grant is real at runtime whatever the
|
|
16
|
-
reason evaluates to, so a non-literal is recorded as its source text rather than dropped."
|
|
17
|
-
|
|
18
|
-
**What this rules out:** discarding a global grant because its value is computed. The
|
|
19
|
-
inspector does not evaluate the expression, so the recorded text is what a later reader
|
|
20
|
-
sees.
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
type: decision
|
|
3
|
-
title: Only one pikkuBetterAuth export is allowed per codebase
|
|
4
|
-
description: pikkuBetterAuth must be an exported const, and a second definition is refused with the first file named
|
|
5
|
-
tags: [inspector, auth, better-auth]
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
# Only one pikkuBetterAuth export is allowed per codebase
|
|
9
|
-
|
|
10
|
-
`addAuth` in `packages/inspector/src/add/add-auth.ts` requires `pikkuBetterAuth(...)`
|
|
11
|
-
to be assigned to an exported `const` (lines 242-248). The message says the CLI has
|
|
12
|
-
to import it.
|
|
13
|
-
|
|
14
|
-
A second definition is refused as critical `DUPLICATE_AUTH_DEFINITION` (lines
|
|
15
|
-
250-256). The message says "Only one pikkuBetterAuth(...) is allowed per codebase"
|
|
16
|
-
and names both the new file and the first one.
|
|
17
|
-
|
|
18
|
-
**What this rules out:** two better-auth configurations in one codebase, so the
|
|
19
|
-
CLI always has a single auth definition to read.
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
type: decision
|
|
3
|
-
title: An undeclared scope and a secret service passed under another name are critical diagnostics
|
|
4
|
-
description: Post-processing reports a function that requires an undeclared scope, and a function-facing service that is a SecretService under another name
|
|
5
|
-
tags: [inspector, scopes, secrets, post-process]
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
# An undeclared scope and a secret service passed under another name are critical diagnostics
|
|
9
|
-
|
|
10
|
-
Both checks run from `packages/inspector/src/inspector.ts`: `validateNoSecretAliasServices` at line
|
|
11
|
-
539, and `validateScopeReferences` at line 579.
|
|
12
|
-
|
|
13
|
-
`validateScopeReferences` in `packages/inspector/src/utils/post-process.ts` (lines 1671-1703) checks each
|
|
14
|
-
function's scopes against the set declared with `defineScope`. A trailing `:*` is stripped before the
|
|
15
|
-
lookup (line 1684). A bare `*` is reported (lines 1686-1692), and an undeclared scope is reported with
|
|
16
|
-
the list of available scopes (lines 1694-1700). Both are `logger.critical` with `ErrorCode.INVALID_VALUE`.
|
|
17
|
-
|
|
18
|
-
`validateNoSecretAliasServices` (lines 1484-1522) reports a function-facing service whose type is a
|
|
19
|
-
`SecretService` under another name. The comment at lines 1479-1482 says a name-based rule would miss
|
|
20
|
-
`pikkuServices(async ({ secrets }) => ({ cfg: secrets }))`, so the check uses the type.
|
|
21
|
-
|
|
22
|
-
**What this rules out:** a function that requires a scope no `defineScope` declares, and a function
|
|
23
|
-
receiving a secret service under a different name.
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
type: decision
|
|
3
|
-
title: Scope segments may not be wildcards or contain colons
|
|
4
|
-
description: The inspector refuses an empty scope segment, a segment containing the separator, and a literal wildcard segment
|
|
5
|
-
tags: [inspector, scopes]
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
# Scope segments may not be wildcards or contain colons
|
|
9
|
-
|
|
10
|
-
`isValidSegment` in `packages/inspector/src/add/add-scope.ts` checks one segment at a
|
|
11
|
-
time and reports each failure as critical:
|
|
12
|
-
|
|
13
|
-
- an empty segment is refused (lines 21-27);
|
|
14
|
-
- a segment containing `:` is refused, with the message telling the author to nest
|
|
15
|
-
with the `scopes` property instead (lines 28-35);
|
|
16
|
-
- a segment equal to `*` is refused, because `*` is reserved for granting a scope
|
|
17
|
-
and its descendants (lines 36-43).
|
|
18
|
-
|
|
19
|
-
`declareScopes` ids are split on `:` and every segment is checked (line 161). Nested
|
|
20
|
-
`scopes` keys are checked the same way (line 77).
|
|
21
|
-
|
|
22
|
-
**What this rules out:** a declared scope that is itself a wildcard, and a scope
|
|
23
|
-
name that hides a second level of nesting inside one segment.
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
type: decision
|
|
3
|
-
title: Shorthand permission entries are extracted, so the audit never reads a guarded function as open
|
|
4
|
-
description: extractPermissionPikkuNames reads { canAdminOrg } shorthand entries in a permissions record as names, as the runtime does
|
|
5
|
-
tags: [inspector, permissions, audit]
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
# Shorthand permission entries are extracted, so the audit never reads a guarded function as open
|
|
9
|
-
|
|
10
|
-
`extractPermissionPikkuNames` in `packages/inspector/src/utils/permissions.ts` (line 15) reads a
|
|
11
|
-
permissions value in two shapes. An array is walked element by element (lines 44-48). An object
|
|
12
|
-
literal is walked property by property (lines 49-62).
|
|
13
|
-
|
|
14
|
-
For a `PropertyAssignment` the initializer is extracted (line 53). For a
|
|
15
|
-
`ShorthandPropertyAssignment`, such as `permissions: { canAdminOrg }`, the property name is
|
|
16
|
-
extracted (lines 54-60).
|
|
17
|
-
|
|
18
|
-
The comment at lines 55-59 says the runtime resolves the shorthand the same way as the longhand
|
|
19
|
-
form, and that dropping it once reported a guarded function as having no permissions.
|
|
20
|
-
|
|
21
|
-
**What this rules out:** an audit that skips shorthand permission entries and so shows a guarded
|
|
22
|
-
function as open.
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
type: decision
|
|
3
|
-
title: System roles must declare literal, unqualified scopes
|
|
4
|
-
description: A system role needs a literal scopes array of string literals, and its name may not contain the scope separator
|
|
5
|
-
tags: [inspector, roles, scopes]
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
# System roles must declare literal, unqualified scopes
|
|
9
|
-
|
|
10
|
-
`addSystemRole` in `packages/inspector/src/add/add-system-role.ts` applies these rules
|
|
11
|
-
to each `defineSystemRole` entry:
|
|
12
|
-
|
|
13
|
-
- `scopes` must be present and must be an array literal. A missing or non-literal
|
|
14
|
-
`scopes` is reported as critical and the role is dropped (lines 37-54, and the
|
|
15
|
-
skip at 143-146). The message asks for `scopes: []` when a role grants nothing
|
|
16
|
-
(line 40).
|
|
17
|
-
- Each element of `scopes` must be a string literal. A non-literal element is
|
|
18
|
-
reported as critical and skipped (lines 57-66). The reason given is that scopes
|
|
19
|
-
are read by AST, so a computed value cannot be checked (line 63).
|
|
20
|
-
- A role name containing `:` is refused (lines 126-133), because `:` delimits scope
|
|
21
|
-
ids and "a role named like a scope reads as one" (line 130).
|
|
22
|
-
- An empty role name is refused (lines 118-124).
|
|
23
|
-
|
|
24
|
-
The doc comment on `extractScopes` (lines 20-23) says the empty array and the
|
|
25
|
-
absent property are kept distinct on purpose.
|
|
26
|
-
|
|
27
|
-
**What this rules out:** a role whose scopes cannot be checked statically, and a
|
|
28
|
-
role name that looks like a scope id.
|
package/knowledge/decisions/the-inspector-records-agent-permissions-only-to-aggregate-services.md
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
type: decision
|
|
3
|
-
title: The inspector records an agent's permissions only to aggregate the services they need, never to check access
|
|
4
|
-
description: addAgent adds the agent's permission names to usedPermissions, and post-process reads that set only to collect each permission's services
|
|
5
|
-
tags: inspector, agents, permissions
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
# The inspector records an agent's permissions only to aggregate the services they need, never to check access
|
|
9
|
-
|
|
10
|
-
`addAgent` resolves the agent's permissions and adds their names to `state.serviceAggregation.usedPermissions` (`packages/inspector/src/add/add-agent.ts:612`, `:618-620`). `post-process.ts` reads the same set at `packages/inspector/src/utils/post-process.ts:160`, and at `:206-209` it adds each used permission's `services` to the service list.
|
|
11
|
-
|
|
12
|
-
Within the inspector source those are the only readers. `serialize-inspector-state.ts` copies the set in and out (`packages/inspector/src/utils/serialize-inspector-state.ts:294`, `:522`, `:746`). Nothing in the inspector compares a caller against the set.
|
|
13
|
-
|
|
14
|
-
**What this rules out:** reading the inspector's agent permission list as evidence that an agent is guarded, and adding an access decision to the inspector's aggregation step.
|
package/knowledge/decisions/vault-secrets-reach-no-sink-and-pii-stays-out-of-logs-and-webhooks.md
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
type: decision
|
|
3
|
-
title: Vault secrets reach no sink, and PII is kept out of logs, the console and webhooks only
|
|
4
|
-
description: check-classified-sinks rejects revealed secrets in every listed sink and PII only in the logger, console and webhook sinks
|
|
5
|
-
tags: [inspector, pii, secrets, lint]
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
# Vault secrets reach no sink, and PII is kept out of logs, the console and webhooks only
|
|
9
|
-
|
|
10
|
-
The sink table in `packages/inspector/src/utils/check-classified-sinks.ts` (lines 44-59) lists
|
|
11
|
-
which methods count as sinks and what each one rejects:
|
|
12
|
-
|
|
13
|
-
- `Logger`, every method, rejects `secret` and `pii` (line 49);
|
|
14
|
-
- `WebhookService.send` rejects `secret` and `pii` (line 50);
|
|
15
|
-
- `QueueService.add` rejects `secret` only (line 51);
|
|
16
|
-
- `EmailService.send` rejects `secret` only (line 52);
|
|
17
|
-
- `AuditService` `audit` and `write` reject `secret` only (lines 53-57);
|
|
18
|
-
- `AuditLog.write` rejects `secret` only (line 58).
|
|
19
|
-
|
|
20
|
-
`console` is handled separately and rejects both (line 62).
|
|
21
|
-
|
|
22
|
-
The comment at lines 23-38 gives the reasons. A vault secret is wrong in every sink (lines 23-24).
|
|
23
|
-
PII is wrong only where it leaves the operator's control or lands somewhere never meant to hold
|
|
24
|
-
it. Lines 37-38 say a queue payload "stays on the operator's own infrastructure", and lines 33-34
|
|
25
|
-
say an email is addressed to the data subject.
|
|
26
|
-
|
|
27
|
-
Lines 40-42 say `private` is absent from the table on purpose.
|
|
28
|
-
|
|
29
|
-
**What this rules out:** a revealed secret reaching any listed sink, and PII reaching a logger,
|
|
30
|
-
the console or a webhook. PII is allowed into queues, email and audit by this table.
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
type: decision
|
|
3
|
-
title: Webhook gateway wrappers are registered sessionless, and gateway auth is enforced inside the handler call
|
|
4
|
-
description: The inspector and the runtime both register a webhook gateway's POST and verify routes as sessionless with auth false, so the route never demands a session and the gateway's own auth flag is applied only when the handler runs
|
|
5
|
-
tags: inspector, gateway, webhook, auth, sessionless
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
# Webhook gateway wrappers are registered sessionless, and gateway auth is enforced inside the handler call
|
|
9
|
-
|
|
10
|
-
**Build time.** For a webhook gateway, `addGateway` writes two function metas, `gateway__<name>__post` and `gateway__<name>__verify`, and their HTTP routes (`packages/inspector/src/add/add-gateway.ts:105-109`). Each function meta is written with `sessionless: true` (`add-gateway.ts:117-122`). The comment on the wrapper says "no middleware here — the gateway POST wrapper runs it itself" (`add-gateway.ts:111`).
|
|
11
|
-
|
|
12
|
-
The gateway's own `auth` flag is not used there. It is recorded only on the gateway meta, as `auth` on `state.gateways.meta[name]` (`add-gateway.ts:135`).
|
|
13
|
-
|
|
14
|
-
**Run time.** `wireWebhookGateway` in `packages/core/src/wirings/gateway/gateway-runner.ts` mirrors this. The POST and verify handlers are both registered with `auth: false` (`gateway-runner.ts:117`, `:141`), and so are their routes (`gateway-runner.ts:130`, `:154`).
|
|
15
|
-
|
|
16
|
-
The POST wrapper, `createWebhookPostHandler` (`gateway-runner.ts:163`), does three things in order:
|
|
17
|
-
|
|
18
|
-
1. If the adapter has `verifyWebhook` and it verifies the request, it returns the adapter's response immediately (`gateway-runner.ts:175-179`). The handler is not reached.
|
|
19
|
-
2. It parses the body; an unparseable body returns `{ ok: true }` (`gateway-runner.ts:182-185`).
|
|
20
|
-
3. It invokes the handler through `runPikkuFunc('gateway', name, handlerFuncId, { ..., auth: config.auth, ... })` (`gateway-runner.ts:196-204`), with gateway middleware running first (`gateway-runner.ts:207-211`).
|
|
21
|
-
|
|
22
|
-
So the session check for a webhook is applied from `CoreGateway.auth`, inside the runner call at `gateway-runner.ts:201`. It is not applied on the HTTP route, which is `auth: false` and sessionless.
|
|
23
|
-
|
|
24
|
-
The synthetic handler registration that this call goes through, and how it inherits the wired function's metadata, is described in [Gateway handlers run through the function runner gate](../../../core/knowledge/decisions/security/gateway-handlers-run-through-the-function-runner-gate.md).
|
|
25
|
-
|
|
26
|
-
**What this rules out:** adding `auth: true` to the POST or verify route to "harden" a webhook. That would reject every platform call, which carries no user session. It also rules out assuming that the route-level metadata shows whether a gateway needs a session. Check `CoreGateway.auth` and the handler's own declaration instead.
|
package/knowledge/index.md
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
type: overview
|
|
3
|
-
title: Knowledge
|
|
4
|
-
description: Why the inspector reads and refuses declarations the way it does
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# Knowledge
|
|
8
|
-
|
|
9
|
-
Why the inspector reads and refuses declarations the way it does — the reasoning that is not visible in the code.
|
|
10
|
-
|
|
11
|
-
<!-- pikku:knowledge-index -->
|
|
12
|
-
- [decisions](decisions/index.md) — a rule that was chosen, and what it rules out
|
|
13
|
-
- [questions](questions/index.md) — something asked and not yet answered
|
|
14
|
-
<!-- /pikku:knowledge-index -->
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
type: question
|
|
3
|
-
title: Does a non-literal auth on wireRemoteAddon get checked?
|
|
4
|
-
description: A non-literal auth value is recorded exactly like an omitted one, so the consumer's credential and secret checks never run for it
|
|
5
|
-
tags: [inspector, addon, auth]
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
# Does a non-literal auth on wireRemoteAddon get checked?
|
|
9
|
-
|
|
10
|
-
`addWireRemoteAddon` in `packages/inspector/src/add/add-wire-remote-addon.ts` reads
|
|
11
|
-
`auth` only when it is an object literal (lines 42-46). Otherwise `hasAuth` stays
|
|
12
|
-
`false` (line 31) and `authCredentialId` and `authSecretId` stay undefined.
|
|
13
|
-
|
|
14
|
-
The comment at lines 27-30 says `hasAuth` separates "public" (omitted) from "bound
|
|
15
|
-
via a custom resolve()" (present, with no static id). A non-literal `auth` value
|
|
16
|
-
therefore looks the same as an omitted one. The declaration is written at lines
|
|
17
|
-
71-78, with `hasAuth` at line 75.
|
|
18
|
-
|
|
19
|
-
Nothing in the inspector reads `hasAuth`. Its only other mentions are the type at
|
|
20
|
-
`packages/inspector/src/types.ts:749` and serialization at
|
|
21
|
-
`packages/inspector/src/utils/serialize-inspector-state.ts:172`. The post-process
|
|
22
|
-
checks run only when an id is set: the credential id at
|
|
23
|
-
`packages/inspector/src/utils/post-process.ts:841` and the secret id at line 847.
|
|
24
|
-
|
|
25
|
-
Question: should a non-literal `auth` be treated as a binding the consumer has to
|
|
26
|
-
satisfy, or as public? The code currently does neither and logs nothing.
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
type: overview
|
|
3
|
-
title: Questions
|
|
4
|
-
description: Things asked of inspector and not yet answered
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# Questions
|
|
8
|
-
|
|
9
|
-
Something asked and not yet answered. The choice stays, the doubt gets recorded.
|
|
10
|
-
|
|
11
|
-
<!-- pikku:knowledge-index -->
|
|
12
|
-
- [Does a non-literal auth on wireRemoteAddon get checked?](does-a-non-literal-remote-addon-auth-get-checked.md) — A non-literal auth value is recorded exactly like an omitted one, so the consumer's credential and secret checks never run for it
|
|
13
|
-
- [Should an incomplete oauth2 block be dropped without a log?](is-an-incomplete-oauth2-block-dropped-without-a-log.md) — An oauth2 block missing any required field is silently left undefined, and an empty scopes array passes the check
|
|
14
|
-
- [Should an app function named like scenario instrumentation be silently skipped?](should-app-functions-named-like-scenario-instrumentation-be-refused.md) — Five instrumentation names are skipped by name in every project, so an app's own function with one of those names disappears without a log
|
|
15
|
-
- [Should the OpenAPI document apply an ApiKey-or-Bearer security default to every operation, including auth false routes?](should-the-openapi-document-default-every-operation-to-a-bearer-or-api-key.md) — The OpenAPI serializer emits one top-level security default for all operations and does not read the auth or session metadata of any route
|
|
16
|
-
<!-- /pikku:knowledge-index -->
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
type: question
|
|
3
|
-
title: Should an incomplete oauth2 block be dropped without a log?
|
|
4
|
-
description: An oauth2 block missing any required field is silently left undefined, and an empty scopes array passes the check
|
|
5
|
-
tags: [inspector, credentials, oauth]
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
# Should an incomplete oauth2 block be dropped without a log?
|
|
9
|
-
|
|
10
|
-
In `packages/inspector/src/add/add-credential.ts`, `oauth2` is set only when
|
|
11
|
-
`appCredentialSecretId`, `authorizationUrl`, `tokenUrl` and `scopes` are all truthy
|
|
12
|
-
(lines 144-155). There is no `else` branch, and nothing in that block calls the
|
|
13
|
-
logger. The credential is still recorded, with `oauth2` undefined.
|
|
14
|
-
|
|
15
|
-
`scopes` comes from `getArrayPropertyValue`, which returns `string[] | null`
|
|
16
|
-
(`packages/inspector/src/utils/get-property-value.ts:22`). An array literal returns
|
|
17
|
-
its string elements even when there are none (lines 31-35). An empty array is
|
|
18
|
-
truthy, so `scopes: []` passes the check.
|
|
19
|
-
|
|
20
|
-
Question: should a half-filled `oauth2` block be reported as critical, as the other
|
|
21
|
-
other validation in the same file is (logger calls at lines 49, 57 and 65)? And should `scopes: []` be
|
|
22
|
-
allowed to satisfy the check at all? The code currently does neither, and no
|
|
23
|
-
comment or test in this path says why.
|
package/knowledge/questions/should-app-functions-named-like-scenario-instrumentation-be-refused.md
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
type: question
|
|
3
|
-
title: Should an app function named like scenario instrumentation be silently skipped?
|
|
4
|
-
description: Five instrumentation names are skipped by name in every project, so an app's own function with one of those names disappears without a log
|
|
5
|
-
tags: [inspector, scenarios, functions]
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
# Should an app function named like scenario instrumentation be silently skipped?
|
|
9
|
-
|
|
10
|
-
`SCENARIO_INSTRUMENTATION_FUNCTIONS` in
|
|
11
|
-
`packages/inspector/src/add/scenario-instrumentation.ts` lists five names (lines
|
|
12
|
-
22-28). `isScenarioInstrumentationFunction` matches them on the id before any `@`
|
|
13
|
-
(lines 40-42).
|
|
14
|
-
|
|
15
|
-
In `packages/inspector/src/add/add-functions.ts`, a function whose id or name matches
|
|
16
|
-
is returned before it is registered (lines 571-576). No logger call happens there.
|
|
17
|
-
The file's comment says the function is "not application code" and must not be
|
|
18
|
-
registered.
|
|
19
|
-
|
|
20
|
-
The file comment gives the reason for matching by name: it keeps an existing
|
|
21
|
-
project's checked-in `scenarios.gen.ts` from deploying (lines 12-15). Lines 17-20
|
|
22
|
-
say `pikkuScenarioGradeRun` is reserved "so an application cannot claim it". No
|
|
23
|
-
comment says the same about the other four names.
|
|
24
|
-
|
|
25
|
-
Question: should an application's own function named `pikkuScenarioResetStubs`,
|
|
26
|
-
`pikkuScenarioGetStubCalls`, `pikkuScenarioTakeLiveCoverage` or
|
|
27
|
-
`pikkuScenarioResetLiveCoverage` be refused with a critical, as the reserved name
|
|
28
|
-
would be, rather than dropped silently?
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
type: question
|
|
3
|
-
title: Should the OpenAPI document apply an ApiKey-or-Bearer security default to every operation, including auth false routes?
|
|
4
|
-
description: The OpenAPI serializer emits one top-level security default for all operations and does not read the auth or session metadata of any route
|
|
5
|
-
tags: [inspector, openapi, auth]
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
# Should the OpenAPI document apply an ApiKey-or-Bearer security default to every operation, including auth false routes?
|
|
9
|
-
|
|
10
|
-
`generateOpenAPISpec` in `packages/inspector/src/utils/serialize-openapi-json.ts` writes two security
|
|
11
|
-
schemes, `ApiKeyAuth` (an `x-api-key` header) and `BearerAuth`, unless the caller supplies its own
|
|
12
|
-
(lines 254-264). It then writes a top-level `security` array with one entry for each scheme
|
|
13
|
-
(lines 266-273), unless the caller supplies one.
|
|
14
|
-
|
|
15
|
-
In OpenAPI a top-level `security` applies to every operation that does not set its own. This file
|
|
16
|
-
does not write per-operation `security`, and a search of the file for `requiresSession` and
|
|
17
|
-
`sessionless` finds nothing. So an operation for a route marked `auth: false` would carry the same
|
|
18
|
-
default as one that requires a session.
|
|
19
|
-
|
|
20
|
-
Question: should `auth: false` routes and sessionless functions be written with an empty
|
|
21
|
-
`security` list, and should the default be applied per operation? The code does not say whether the
|
|
22
|
-
default is meant for the whole API or only as a placeholder.
|
package/run-tests.sh
DELETED
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
|
|
3
|
-
# Enable nullglob to handle cases where no files match the pattern
|
|
4
|
-
shopt -s nullglob
|
|
5
|
-
|
|
6
|
-
# Initialize variables for options
|
|
7
|
-
watch_mode=false
|
|
8
|
-
coverage_mode=false
|
|
9
|
-
|
|
10
|
-
# Parse command-line options
|
|
11
|
-
while [[ $# -gt 0 ]]; do
|
|
12
|
-
case $1 in
|
|
13
|
-
--watch)
|
|
14
|
-
watch_mode=true
|
|
15
|
-
shift
|
|
16
|
-
;;
|
|
17
|
-
--coverage)
|
|
18
|
-
coverage_mode=true
|
|
19
|
-
shift
|
|
20
|
-
;;
|
|
21
|
-
*)
|
|
22
|
-
echo "Unknown option: $1"
|
|
23
|
-
exit 1
|
|
24
|
-
;;
|
|
25
|
-
esac
|
|
26
|
-
done
|
|
27
|
-
|
|
28
|
-
# Define the pattern to match your test files
|
|
29
|
-
pattern="src/*.test.ts"
|
|
30
|
-
|
|
31
|
-
# Expand the pattern into an array of files
|
|
32
|
-
files=($(find src -type f -name "*.test.ts"))
|
|
33
|
-
|
|
34
|
-
# Check if any files matched the pattern
|
|
35
|
-
if [ ${#files[@]} -eq 0 ]; then
|
|
36
|
-
echo "No test files found matching pattern: $pattern"
|
|
37
|
-
if [ "${STRICT_TEST_DISCOVERY}" = "1" ]; then
|
|
38
|
-
exit 1
|
|
39
|
-
fi
|
|
40
|
-
exit 0
|
|
41
|
-
fi
|
|
42
|
-
|
|
43
|
-
# Construct the bun command
|
|
44
|
-
#
|
|
45
|
-
# --parallel gives every test file its own worker process, which is what node's
|
|
46
|
-
# `--test` did. Several suites keep module-level caches (a TypeScript program, a
|
|
47
|
-
# temp fixture directory) that a shared process would leak between files.
|
|
48
|
-
#
|
|
49
|
-
# --timeout because bun caps a test at 5s by default where node had no cap, and
|
|
50
|
-
# the suites that build real TypeScript programs run well past that.
|
|
51
|
-
bun_cmd=(bun test --parallel --timeout 120000)
|
|
52
|
-
|
|
53
|
-
# Append options based on flags
|
|
54
|
-
if [ "$watch_mode" = true ]; then
|
|
55
|
-
# --watch reruns in one process; parallel workers have nothing to watch.
|
|
56
|
-
bun_cmd=(bun test --watch --timeout 120000)
|
|
57
|
-
fi
|
|
58
|
-
|
|
59
|
-
if [ "$coverage_mode" = true ]; then
|
|
60
|
-
# --coverage-dir=. keeps lcov.info at the package root: CI merges every
|
|
61
|
-
# package's report by prefixing its SF paths with the file's own directory,
|
|
62
|
-
# so a nested coverage/ directory would re-root them one level too deep.
|
|
63
|
-
bun_cmd+=(--coverage --coverage-reporter=lcov --coverage-reporter=text --coverage-dir=.)
|
|
64
|
-
export PIKKU_TEST_COVERAGE=1
|
|
65
|
-
fi
|
|
66
|
-
|
|
67
|
-
# Execute the bun command with the expanded list of files
|
|
68
|
-
"${bun_cmd[@]}" "${files[@]}"
|