@suss/contract-wrangler 0.33.1 → 0.34.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -17
- package/dist/index.cjs +5 -5
- package/dist/index.d.cts +34 -35
- package/dist/index.d.ts +34 -35
- package/dist/index.js +5 -5
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
# @suss/contract-wrangler
|
|
2
2
|
|
|
3
|
-
Part of [suss](https://github.com/nimbuscloud-ai/suss), which reads both sides of every call in a repository and
|
|
3
|
+
Part of [suss](https://github.com/nimbuscloud-ai/suss), which reads both sides of every call in a repository and reports where the two disagree.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
This package reads a Cloudflare `wrangler.toml` (or `wrangler.jsonc`) and records what the Worker it deploys is given.
|
|
6
6
|
|
|
7
7
|
## What this package is
|
|
8
8
|
|
|
9
|
-
A contract source. `suss contract --from wrangler services/api` reads the document and
|
|
9
|
+
A contract source. `suss contract --from wrangler services/api` reads the document and records the declared side of four boundaries:
|
|
10
10
|
|
|
11
11
|
```toml
|
|
12
12
|
name = "greeting-router"
|
|
@@ -31,39 +31,39 @@ queue = "greeting-events"
|
|
|
31
31
|
| `[[queues.producers]]`, `[[queues.consumers]]` | one channel each, on `cloudflare-queues` |
|
|
32
32
|
| `[env.<name>]` | the same Worker deployed again, with the top-level document as its default |
|
|
33
33
|
|
|
34
|
-
A store's container is the binding name, `SESSIONS`, because that is what an access in the Worker
|
|
34
|
+
A store's container is the binding name, `SESSIONS`, because that is what an access in the Worker uses (`env.SESSIONS.get(...)`). `@suss/framework-cloudflare-workers` records the same name on the code side, so the storage check pairs the two. The resource's own name, meaning the KV namespace id or the bucket name, goes on the summary as `physicalTable`. A Prisma model splits the same way, between the model name and the table it maps to.
|
|
35
35
|
|
|
36
|
-
Binding names are also listed on the runtime-config contract,
|
|
36
|
+
Binding names are also listed on the runtime-config contract, next to the `[vars]` names. A binding is a property of the same `env` object, so a Worker that reads `env.AUDIT_KV` with no binding block for it gets the same finding as a read of a variable nobody set.
|
|
37
37
|
|
|
38
|
-
##
|
|
38
|
+
## Variable values
|
|
39
39
|
|
|
40
|
-
A runtime-config contract usually records which variables a runtime supplies, and that is enough to
|
|
40
|
+
A runtime-config contract usually records which variables a runtime supplies, and that is enough to tell whether code reads one nobody set. A Worker needs more, because it addresses its stores through a variable:
|
|
41
41
|
|
|
42
42
|
```ts
|
|
43
43
|
await dynamoRequest(env, aws, "Query", { TableName: env.EDITION_TABLE });
|
|
44
44
|
```
|
|
45
45
|
|
|
46
|
-
Nothing at that call site
|
|
46
|
+
Nothing at that call site shows which table. The container comes out as `{EDITION_TABLE}`, which does not pair with anything until something gives the variable's value. `[vars]` gives it, so the summary keeps the values under `metadata.runtimeContract.envVarValues`, and the storage check grounds the access through the runtime that runs it.
|
|
47
47
|
|
|
48
|
-
A value the document does not
|
|
48
|
+
A value the document does not set is left out. A secret is set with `wrangler secret put` or by the deployment's own tooling, and never in the file, so the reader has nothing to record and the container stays unresolved.
|
|
49
49
|
|
|
50
50
|
## Environments
|
|
51
51
|
|
|
52
|
-
`[env.staging]` deploys the same Worker again under its own name, `greeting-router-staging` unless the block
|
|
52
|
+
`[env.staging]` deploys the same Worker again under its own name, which is `greeting-router-staging` unless the block sets a `name`. Each environment gets its own summary.
|
|
53
53
|
|
|
54
|
-
Wrangler replaces a whole block
|
|
54
|
+
Wrangler replaces a whole block instead of merging it, so an environment that declares `[env.staging.vars]` gets those variables and none of the top-level ones. A variable that comes through unchanged is recorded as `globals`, the same provenance a SAM `Globals` section gets, and the checker judges it once for the document instead of once per deployment.
|
|
55
55
|
|
|
56
56
|
## Code scope
|
|
57
57
|
|
|
58
|
-
The Worker's code is the directory the document is in, and `main`
|
|
58
|
+
The Worker's code is the directory the document is in, and `main` gives the entry file. `main` often points at a bundle that a build step writes, outside the source. If the entry matches no file, the directory alone decides the code scope, so the code is placed correctly either way.
|
|
59
59
|
|
|
60
60
|
## Out of scope for now
|
|
61
61
|
|
|
62
|
-
- **Durable Object and service bindings.** `[[durable_objects.bindings]]` and `[[services]]` are boundaries between two Workers, and pairing them needs both sides of a deployment suss does not read yet.
|
|
63
|
-
- **Routes.** `routes`
|
|
64
|
-
- **Cron expressions.** `[triggers] crons`
|
|
65
|
-
- **`.dev.vars`.** It is local development
|
|
62
|
+
- **Durable Object and service bindings.** `[[durable_objects.bindings]]` and `[[services]]` are boundaries between two Workers, and pairing them needs both sides of a deployment, which suss does not read yet.
|
|
63
|
+
- **Routes.** `routes` lists the hostnames that reach the Worker. The code side does not state a path, so a declared route would not pair with anything.
|
|
64
|
+
- **Cron expressions.** `[triggers] crons` sets when a Worker runs, and says nothing about what it exchanges.
|
|
65
|
+
- **`.dev.vars`.** It is configuration for local development, and a deployment does not supply it.
|
|
66
66
|
|
|
67
67
|
## Where it fits in suss
|
|
68
68
|
|
|
69
|
-
|
|
69
|
+
The package depends on `@suss/behavioral-ir` and `@suss/ir-core` for the bindings it writes. `@suss/framework-cloudflare-workers` reads the code side: the triggers the Worker serves and the variables it reads. The storage check in `@suss/checker` pairs a store this reader declares, or one a Terraform module declares, with the accesses that reach it.
|
package/dist/index.cjs
CHANGED
|
@@ -98,8 +98,8 @@ function storeSummary(store, entry, context) {
|
|
|
98
98
|
recognition: RECOGNITION,
|
|
99
99
|
storageSystem: store.storageSystem,
|
|
100
100
|
scope: "default",
|
|
101
|
-
//
|
|
102
|
-
//
|
|
101
|
+
// An access in the Worker uses the binding name, so the storage
|
|
102
|
+
// check has to pair on it.
|
|
103
103
|
container: boundAs ?? resourceName,
|
|
104
104
|
accessPath: null
|
|
105
105
|
})
|
|
@@ -164,9 +164,9 @@ function queueSide(entries, side, context) {
|
|
|
164
164
|
continue;
|
|
165
165
|
}
|
|
166
166
|
summaries.push({
|
|
167
|
-
// A producer block declares a queue the Worker sends to
|
|
168
|
-
//
|
|
169
|
-
//
|
|
167
|
+
// A producer block declares a queue the Worker sends to. Nothing
|
|
168
|
+
// runs there, so it is a library. A consumer block means this
|
|
169
|
+
// Worker drains the queue.
|
|
170
170
|
kind: side === "consumers" ? "consumer" : "library",
|
|
171
171
|
location: {
|
|
172
172
|
file: context.sourceFile,
|
package/dist/index.d.cts
CHANGED
|
@@ -3,15 +3,14 @@ import { BehavioralSummary } from '@suss/behavioral-ir';
|
|
|
3
3
|
/**
|
|
4
4
|
* Finding and parsing a Wrangler configuration document.
|
|
5
5
|
*
|
|
6
|
-
* Wrangler accepts the same configuration
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
6
|
+
* Wrangler accepts the same configuration as TOML or JSONC, and uses the
|
|
7
|
+
* JSON file when a project has both. This module picks the file for a
|
|
8
|
+
* path and returns the parsed object. It does not check the object's
|
|
9
|
+
* contents beyond it being an object.
|
|
10
10
|
*/
|
|
11
11
|
/**
|
|
12
|
-
* The names Wrangler looks for, in
|
|
13
|
-
*
|
|
14
|
-
* the path to that file outright.
|
|
12
|
+
* The file names Wrangler looks for, in its order of preference. A
|
|
13
|
+
* project whose file has another name passes that file's path directly.
|
|
15
14
|
*/
|
|
16
15
|
declare const CONFIGURATION_FILE_NAMES: string[];
|
|
17
16
|
/** Whether a file is one Wrangler would read as a Worker's configuration. */
|
|
@@ -44,24 +43,22 @@ type DocumentLocation = {
|
|
|
44
43
|
kind: "missing";
|
|
45
44
|
};
|
|
46
45
|
/**
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
46
|
+
* Finds the configuration file for a path. The path may be the file
|
|
47
|
+
* itself or the Worker's directory, which is searched in Wrangler's
|
|
48
|
+
* order of preference.
|
|
50
49
|
*/
|
|
51
50
|
declare function locateConfigurationFile(target: string): DocumentLocation;
|
|
52
|
-
/**
|
|
51
|
+
/** Parses a configuration file as TOML or JSONC, chosen by its extension. */
|
|
53
52
|
declare function loadConfigurationDocument(file: string): WranglerDocument;
|
|
54
53
|
|
|
55
54
|
/**
|
|
56
55
|
* The stores and queues a Worker is bound to, as boundary summaries.
|
|
57
56
|
*
|
|
58
|
-
* Every binding block in a Wrangler document has
|
|
59
|
-
*
|
|
60
|
-
* resource's own name.
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
* and `physicalTable` is the resource's own name, the same split a
|
|
64
|
-
* Prisma model has between the model and the table it maps to.
|
|
57
|
+
* Every binding block in a Wrangler document has two parts: `binding`,
|
|
58
|
+
* the name the code reads the resource under, and a key with the
|
|
59
|
+
* resource's own name. Code only ever uses the first (`env.SESSIONS`),
|
|
60
|
+
* so the binding name becomes the container the storage check pairs
|
|
61
|
+
* on, and the resource's own name goes on `physicalTable`.
|
|
65
62
|
*/
|
|
66
63
|
|
|
67
64
|
/** The manifest language recorded on every binding this reader writes. */
|
|
@@ -71,14 +68,15 @@ declare const RECOGNITION = "wrangler";
|
|
|
71
68
|
* The configuration contract a Wrangler document declares.
|
|
72
69
|
*
|
|
73
70
|
* A Worker reads its variables off the second argument to every
|
|
74
|
-
* trigger
|
|
75
|
-
* `process.env`,
|
|
76
|
-
*
|
|
77
|
-
*
|
|
71
|
+
* trigger. That is the same channel a Node process reads through
|
|
72
|
+
* `process.env`, so the summary follows what the CloudFormation reader
|
|
73
|
+
* writes for a Lambda: one runtime-config provider per deployment, keyed
|
|
74
|
+
* on the deployable unit.
|
|
78
75
|
*
|
|
79
|
-
* The
|
|
80
|
-
*
|
|
81
|
-
* so the value
|
|
76
|
+
* The summary records variable values as well as names. A Worker
|
|
77
|
+
* addresses a store through a variable, as in
|
|
78
|
+
* `TableName: env.EDITION_TABLE`, so only the value shows which store
|
|
79
|
+
* the access reaches.
|
|
82
80
|
*/
|
|
83
81
|
|
|
84
82
|
/** One Worker as deployed: an environment's document over the default one. */
|
|
@@ -89,7 +87,7 @@ interface Deployment {
|
|
|
89
87
|
environment: string | null;
|
|
90
88
|
/** The environment's document with the top-level one behind it. */
|
|
91
89
|
merged: WranglerDocument;
|
|
92
|
-
/**
|
|
90
|
+
/** The variables and bindings this environment takes from the top level. */
|
|
93
91
|
inherited: Set<string>;
|
|
94
92
|
}
|
|
95
93
|
/**
|
|
@@ -104,14 +102,12 @@ declare function environmentDocuments(document: WranglerDocument): Deployment[];
|
|
|
104
102
|
* @suss/contract-wrangler: behavioral summaries from a Wrangler
|
|
105
103
|
* configuration document.
|
|
106
104
|
*
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
*
|
|
110
|
-
*
|
|
111
|
-
*
|
|
112
|
-
*
|
|
113
|
-
* the top-level document as its default. The README says how each half
|
|
114
|
-
* pairs.
|
|
105
|
+
* `name` and `main` give the deployable unit and the code it runs.
|
|
106
|
+
* `vars` gives its configuration, the three binding blocks give its
|
|
107
|
+
* stores, and `queues` gives the channels it sends on and drains. Each
|
|
108
|
+
* `env.<name>` deploys the same Worker again, with the top-level
|
|
109
|
+
* document as its default. The README describes how each summary pairs
|
|
110
|
+
* with the code side.
|
|
115
111
|
*/
|
|
116
112
|
|
|
117
113
|
interface WranglerToSummariesOptions {
|
|
@@ -128,7 +124,10 @@ declare function wranglerToSummaries(document: WranglerDocument, options: {
|
|
|
128
124
|
source: string;
|
|
129
125
|
codeScope: string;
|
|
130
126
|
}): BehavioralSummary[];
|
|
131
|
-
/**
|
|
127
|
+
/**
|
|
128
|
+
* Reads a Wrangler document and returns its summaries. The path may be
|
|
129
|
+
* the document itself or the directory the Worker is in.
|
|
130
|
+
*/
|
|
132
131
|
declare function wranglerFileToSummaries(target: string, options?: WranglerToSummariesOptions): BehavioralSummary[];
|
|
133
132
|
|
|
134
133
|
export { CONFIGURATION_FILE_NAMES, type DocumentLocation, RECOGNITION, type WranglerDocument, type WranglerRecord, type WranglerToSummariesOptions, environmentDocuments, isConfigurationFile, loadConfigurationDocument, locateConfigurationFile, wranglerFileToSummaries, wranglerToSummaries };
|
package/dist/index.d.ts
CHANGED
|
@@ -3,15 +3,14 @@ import { BehavioralSummary } from '@suss/behavioral-ir';
|
|
|
3
3
|
/**
|
|
4
4
|
* Finding and parsing a Wrangler configuration document.
|
|
5
5
|
*
|
|
6
|
-
* Wrangler accepts the same configuration
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
6
|
+
* Wrangler accepts the same configuration as TOML or JSONC, and uses the
|
|
7
|
+
* JSON file when a project has both. This module picks the file for a
|
|
8
|
+
* path and returns the parsed object. It does not check the object's
|
|
9
|
+
* contents beyond it being an object.
|
|
10
10
|
*/
|
|
11
11
|
/**
|
|
12
|
-
* The names Wrangler looks for, in
|
|
13
|
-
*
|
|
14
|
-
* the path to that file outright.
|
|
12
|
+
* The file names Wrangler looks for, in its order of preference. A
|
|
13
|
+
* project whose file has another name passes that file's path directly.
|
|
15
14
|
*/
|
|
16
15
|
declare const CONFIGURATION_FILE_NAMES: string[];
|
|
17
16
|
/** Whether a file is one Wrangler would read as a Worker's configuration. */
|
|
@@ -44,24 +43,22 @@ type DocumentLocation = {
|
|
|
44
43
|
kind: "missing";
|
|
45
44
|
};
|
|
46
45
|
/**
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
46
|
+
* Finds the configuration file for a path. The path may be the file
|
|
47
|
+
* itself or the Worker's directory, which is searched in Wrangler's
|
|
48
|
+
* order of preference.
|
|
50
49
|
*/
|
|
51
50
|
declare function locateConfigurationFile(target: string): DocumentLocation;
|
|
52
|
-
/**
|
|
51
|
+
/** Parses a configuration file as TOML or JSONC, chosen by its extension. */
|
|
53
52
|
declare function loadConfigurationDocument(file: string): WranglerDocument;
|
|
54
53
|
|
|
55
54
|
/**
|
|
56
55
|
* The stores and queues a Worker is bound to, as boundary summaries.
|
|
57
56
|
*
|
|
58
|
-
* Every binding block in a Wrangler document has
|
|
59
|
-
*
|
|
60
|
-
* resource's own name.
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
* and `physicalTable` is the resource's own name, the same split a
|
|
64
|
-
* Prisma model has between the model and the table it maps to.
|
|
57
|
+
* Every binding block in a Wrangler document has two parts: `binding`,
|
|
58
|
+
* the name the code reads the resource under, and a key with the
|
|
59
|
+
* resource's own name. Code only ever uses the first (`env.SESSIONS`),
|
|
60
|
+
* so the binding name becomes the container the storage check pairs
|
|
61
|
+
* on, and the resource's own name goes on `physicalTable`.
|
|
65
62
|
*/
|
|
66
63
|
|
|
67
64
|
/** The manifest language recorded on every binding this reader writes. */
|
|
@@ -71,14 +68,15 @@ declare const RECOGNITION = "wrangler";
|
|
|
71
68
|
* The configuration contract a Wrangler document declares.
|
|
72
69
|
*
|
|
73
70
|
* A Worker reads its variables off the second argument to every
|
|
74
|
-
* trigger
|
|
75
|
-
* `process.env`,
|
|
76
|
-
*
|
|
77
|
-
*
|
|
71
|
+
* trigger. That is the same channel a Node process reads through
|
|
72
|
+
* `process.env`, so the summary follows what the CloudFormation reader
|
|
73
|
+
* writes for a Lambda: one runtime-config provider per deployment, keyed
|
|
74
|
+
* on the deployable unit.
|
|
78
75
|
*
|
|
79
|
-
* The
|
|
80
|
-
*
|
|
81
|
-
* so the value
|
|
76
|
+
* The summary records variable values as well as names. A Worker
|
|
77
|
+
* addresses a store through a variable, as in
|
|
78
|
+
* `TableName: env.EDITION_TABLE`, so only the value shows which store
|
|
79
|
+
* the access reaches.
|
|
82
80
|
*/
|
|
83
81
|
|
|
84
82
|
/** One Worker as deployed: an environment's document over the default one. */
|
|
@@ -89,7 +87,7 @@ interface Deployment {
|
|
|
89
87
|
environment: string | null;
|
|
90
88
|
/** The environment's document with the top-level one behind it. */
|
|
91
89
|
merged: WranglerDocument;
|
|
92
|
-
/**
|
|
90
|
+
/** The variables and bindings this environment takes from the top level. */
|
|
93
91
|
inherited: Set<string>;
|
|
94
92
|
}
|
|
95
93
|
/**
|
|
@@ -104,14 +102,12 @@ declare function environmentDocuments(document: WranglerDocument): Deployment[];
|
|
|
104
102
|
* @suss/contract-wrangler: behavioral summaries from a Wrangler
|
|
105
103
|
* configuration document.
|
|
106
104
|
*
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
*
|
|
110
|
-
*
|
|
111
|
-
*
|
|
112
|
-
*
|
|
113
|
-
* the top-level document as its default. The README says how each half
|
|
114
|
-
* pairs.
|
|
105
|
+
* `name` and `main` give the deployable unit and the code it runs.
|
|
106
|
+
* `vars` gives its configuration, the three binding blocks give its
|
|
107
|
+
* stores, and `queues` gives the channels it sends on and drains. Each
|
|
108
|
+
* `env.<name>` deploys the same Worker again, with the top-level
|
|
109
|
+
* document as its default. The README describes how each summary pairs
|
|
110
|
+
* with the code side.
|
|
115
111
|
*/
|
|
116
112
|
|
|
117
113
|
interface WranglerToSummariesOptions {
|
|
@@ -128,7 +124,10 @@ declare function wranglerToSummaries(document: WranglerDocument, options: {
|
|
|
128
124
|
source: string;
|
|
129
125
|
codeScope: string;
|
|
130
126
|
}): BehavioralSummary[];
|
|
131
|
-
/**
|
|
127
|
+
/**
|
|
128
|
+
* Reads a Wrangler document and returns its summaries. The path may be
|
|
129
|
+
* the document itself or the directory the Worker is in.
|
|
130
|
+
*/
|
|
132
131
|
declare function wranglerFileToSummaries(target: string, options?: WranglerToSummariesOptions): BehavioralSummary[];
|
|
133
132
|
|
|
134
133
|
export { CONFIGURATION_FILE_NAMES, type DocumentLocation, RECOGNITION, type WranglerDocument, type WranglerRecord, type WranglerToSummariesOptions, environmentDocuments, isConfigurationFile, loadConfigurationDocument, locateConfigurationFile, wranglerFileToSummaries, wranglerToSummaries };
|
package/dist/index.js
CHANGED
|
@@ -57,8 +57,8 @@ function storeSummary(store, entry, context) {
|
|
|
57
57
|
recognition: RECOGNITION,
|
|
58
58
|
storageSystem: store.storageSystem,
|
|
59
59
|
scope: "default",
|
|
60
|
-
//
|
|
61
|
-
//
|
|
60
|
+
// An access in the Worker uses the binding name, so the storage
|
|
61
|
+
// check has to pair on it.
|
|
62
62
|
container: boundAs ?? resourceName,
|
|
63
63
|
accessPath: null
|
|
64
64
|
})
|
|
@@ -123,9 +123,9 @@ function queueSide(entries, side, context) {
|
|
|
123
123
|
continue;
|
|
124
124
|
}
|
|
125
125
|
summaries.push({
|
|
126
|
-
// A producer block declares a queue the Worker sends to
|
|
127
|
-
//
|
|
128
|
-
//
|
|
126
|
+
// A producer block declares a queue the Worker sends to. Nothing
|
|
127
|
+
// runs there, so it is a library. A consumer block means this
|
|
128
|
+
// Worker drains the queue.
|
|
129
129
|
kind: side === "consumers" ? "consumer" : "library",
|
|
130
130
|
location: {
|
|
131
131
|
file: context.sourceFile,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@suss/contract-wrangler",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.34.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Read a Cloudflare wrangler.toml or wrangler.jsonc and check the bindings it declares against the Worker code that uses them.",
|
|
6
6
|
"keywords": [
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
],
|
|
15
15
|
"license": "Apache-2.0",
|
|
16
16
|
"author": "Nimbus Cloud AI LLC",
|
|
17
|
-
"homepage": "https://
|
|
17
|
+
"homepage": "https://suss.sh",
|
|
18
18
|
"repository": {
|
|
19
19
|
"type": "git",
|
|
20
20
|
"url": "git+https://github.com/nimbuscloud-ai/suss.git",
|
|
@@ -47,8 +47,8 @@
|
|
|
47
47
|
"typecheck": "tsc --noEmit"
|
|
48
48
|
},
|
|
49
49
|
"dependencies": {
|
|
50
|
-
"@suss/behavioral-ir": "0.
|
|
51
|
-
"@suss/ir-core": "0.
|
|
50
|
+
"@suss/behavioral-ir": "0.34.0",
|
|
51
|
+
"@suss/ir-core": "0.34.0",
|
|
52
52
|
"jsonc-parser": "^3.3.1",
|
|
53
53
|
"smol-toml": "^1.4.2"
|
|
54
54
|
},
|