@mccaskie-labs/workbench-config 0.1.24 → 0.1.26

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/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @mccaskie-labs/workbench-config
2
2
 
3
+ ## 0.1.26
4
+
5
+ ### Patch Changes
6
+
7
+ - The database manifest gains the sign-in bot check: Control's `cf_turnstile_widget_create` and `cf_turnstile_widget_delete`, the `TURNSTILE_SITE_KEY` and `TURNSTILE_SECRET_KEY` config (written by `cf_worker_secret_put` sources `turnstile_sitekey` and `turnstile_secret`), the rule `database.sign-in-checks-for-bots` and its drill probe `database.sign-in-bot-check`.
8
+
9
+ ## 0.1.25
10
+
11
+ ### Patch Changes
12
+
13
+ - Vendor settings baseline: two new Supabase Auth rows. `supabase.auth.signup_skips_email_confirm` keeps "Confirm email" on (`mailer_autoconfirm` false), and `supabase.auth.anonymous_sign_ins` keeps anonymous sign-ins off (`external_anonymous_users_enabled` false). An app that trusts the email in a session is only safe while both hold.
14
+
3
15
  ## 0.1.24
4
16
 
5
17
  ### Patch Changes
@@ -24,7 +24,9 @@
24
24
  "sb_query",
25
25
  "sb_project_delete",
26
26
  "cf_worker_secret_put",
27
- "vendor_settings_apply"
27
+ "vendor_settings_apply",
28
+ "cf_turnstile_widget_create",
29
+ "cf_turnstile_widget_delete"
28
30
  ]
29
31
  },
30
32
  "config": [
@@ -70,6 +72,28 @@
70
72
  "production"
71
73
  ],
72
74
  "description": "Seals the sign-in session cookie (createSessions). 32 random bytes written by cf_worker_secret_put source=generate:32; replacing it signs everybody out, so it is two-step. Only needed by an app with sign-in"
75
+ },
76
+ {
77
+ "name": "TURNSTILE_SITE_KEY",
78
+ "required": false,
79
+ "secret": false,
80
+ "environments": [
81
+ "development",
82
+ "staging",
83
+ "production"
84
+ ],
85
+ "description": "The public site key of the hostname's Turnstile widget, for the sign-in bot check; written by cf_worker_secret_put source=turnstile_sitekey after cf_turnstile_widget_create. Outside development, sign-in won't send codes without it"
86
+ },
87
+ {
88
+ "name": "TURNSTILE_SECRET_KEY",
89
+ "required": false,
90
+ "secret": true,
91
+ "environments": [
92
+ "development",
93
+ "staging",
94
+ "production"
95
+ ],
96
+ "description": "The secret of the hostname's Turnstile widget, sent only to Cloudflare's Siteverify; written by cf_worker_secret_put source=turnstile_secret. Outside development, sign-in won't send codes without it"
73
97
  }
74
98
  ],
75
99
  "actions": [
@@ -104,7 +128,7 @@
104
128
  {
105
129
  "tool": "cf_worker_secret_put",
106
130
  "gate": "two_step_when",
107
- "when": "source supabase_secret, or replacing a secret that exists",
131
+ "when": "source supabase_secret, or replacing a secret that exists (not sources web_analytics, turnstile_sitekey or turnstile_secret, whose value comes from the recorded resource)",
108
132
  "ships": "4"
109
133
  },
110
134
  {
@@ -112,6 +136,16 @@
112
136
  "gate": "two_step_when",
113
137
  "when": "production, after the first successful apply on that database; staging and check_only are free",
114
138
  "ships": "5"
139
+ },
140
+ {
141
+ "tool": "cf_turnstile_widget_create",
142
+ "gate": "free",
143
+ "ships": "5"
144
+ },
145
+ {
146
+ "tool": "cf_turnstile_widget_delete",
147
+ "gate": "two_step",
148
+ "ships": "5"
115
149
  }
116
150
  ],
117
151
  "rules": [
@@ -170,6 +204,13 @@
170
204
  "text": "Refuse a write (anything but GET or HEAD) made with the session cookie unless sameOrigin(request) is true.",
171
205
  "enforced_by": "review",
172
206
  "probe": "database.session-cookie"
207
+ },
208
+ {
209
+ "id": "database.sign-in-checks-for-bots",
210
+ "kind": "must",
211
+ "text": "Outside development, verify a Turnstile token with Siteverify (success, this hostname and the sign-in action) before asking Supabase to send or re-send a sign-in code, and send no code when either Turnstile key is missing.",
212
+ "enforced_by": "review",
213
+ "probe": "database.sign-in-bot-check"
173
214
  }
174
215
  ],
175
216
  "examples": [
@@ -252,6 +293,13 @@
252
293
  "expect": "pass",
253
294
  "cost_hint_usd": 0,
254
295
  "note": "The session cookie is __Host-, Secure, HttpOnly, SameSite=Lax and sealed; a cross-site write is refused; sign-out clears it with every attribute"
296
+ },
297
+ {
298
+ "id": "database.sign-in-bot-check",
299
+ "half": "drill",
300
+ "expect": "pass",
301
+ "cost_hint_usd": 0,
302
+ "note": "On a project's staging: cf_turnstile_widget_create and the turnstile_sitekey and turnstile_secret sources; the sign-in page shows the check, /auth/code without a passed token sends no code, and with one it does"
255
303
  }
256
304
  ]
257
305
  }
@@ -1,4 +1,4 @@
1
- export declare const MANIFEST_VERSION: "ecc54c728515";
1
+ export declare const MANIFEST_VERSION: "7d046814165b";
2
2
  export declare const capabilities: {
3
3
  readonly ai: {
4
4
  readonly $schema: "./schema.json";
@@ -421,7 +421,7 @@ export declare const capabilities: {
421
421
  readonly summary: "Each project has its own Supabase projects, <id>-staging and <id>-production. Apps use them natively through workbench-supabase; Control creates them, writes their URL and keys onto the Workers, and applies migrations read from the repo.";
422
422
  readonly status: "built";
423
423
  readonly surfaces: {
424
- readonly tools: readonly ["sb_project_create", "sb_migration_apply", "sb_migration_rollback", "sb_query", "sb_project_delete", "cf_worker_secret_put", "vendor_settings_apply"];
424
+ readonly tools: readonly ["sb_project_create", "sb_migration_apply", "sb_migration_rollback", "sb_query", "sb_project_delete", "cf_worker_secret_put", "vendor_settings_apply", "cf_turnstile_widget_create", "cf_turnstile_widget_delete"];
425
425
  readonly package: readonly ["supabaseConfig", "createBrowserClient", "createServerClient", "createUserClient", "createServiceClient", "WorkbenchSupabaseError", "createSessions", "safeReturnPath", "sameOrigin"];
426
426
  };
427
427
  readonly config: readonly [{
@@ -448,6 +448,18 @@ export declare const capabilities: {
448
448
  readonly secret: true;
449
449
  readonly environments: readonly ["development", "staging", "production"];
450
450
  readonly description: "Seals the sign-in session cookie (createSessions). 32 random bytes written by cf_worker_secret_put source=generate:32; replacing it signs everybody out, so it is two-step. Only needed by an app with sign-in";
451
+ }, {
452
+ readonly name: "TURNSTILE_SITE_KEY";
453
+ readonly required: false;
454
+ readonly secret: false;
455
+ readonly environments: readonly ["development", "staging", "production"];
456
+ readonly description: "The public site key of the hostname's Turnstile widget, for the sign-in bot check; written by cf_worker_secret_put source=turnstile_sitekey after cf_turnstile_widget_create. Outside development, sign-in won't send codes without it";
457
+ }, {
458
+ readonly name: "TURNSTILE_SECRET_KEY";
459
+ readonly required: false;
460
+ readonly secret: true;
461
+ readonly environments: readonly ["development", "staging", "production"];
462
+ readonly description: "The secret of the hostname's Turnstile widget, sent only to Cloudflare's Siteverify; written by cf_worker_secret_put source=turnstile_secret. Outside development, sign-in won't send codes without it";
451
463
  }];
452
464
  readonly actions: readonly [{
453
465
  readonly tool: "sb_project_create";
@@ -475,13 +487,21 @@ export declare const capabilities: {
475
487
  }, {
476
488
  readonly tool: "cf_worker_secret_put";
477
489
  readonly gate: "two_step_when";
478
- readonly when: "source supabase_secret, or replacing a secret that exists";
490
+ readonly when: "source supabase_secret, or replacing a secret that exists (not sources web_analytics, turnstile_sitekey or turnstile_secret, whose value comes from the recorded resource)";
479
491
  readonly ships: "4";
480
492
  }, {
481
493
  readonly tool: "vendor_settings_apply";
482
494
  readonly gate: "two_step_when";
483
495
  readonly when: "production, after the first successful apply on that database; staging and check_only are free";
484
496
  readonly ships: "5";
497
+ }, {
498
+ readonly tool: "cf_turnstile_widget_create";
499
+ readonly gate: "free";
500
+ readonly ships: "5";
501
+ }, {
502
+ readonly tool: "cf_turnstile_widget_delete";
503
+ readonly gate: "two_step";
504
+ readonly ships: "5";
485
505
  }];
486
506
  readonly rules: readonly [{
487
507
  readonly id: "database.rls-isolates-users";
@@ -531,6 +551,12 @@ export declare const capabilities: {
531
551
  readonly text: "Refuse a write (anything but GET or HEAD) made with the session cookie unless sameOrigin(request) is true.";
532
552
  readonly enforced_by: "review";
533
553
  readonly probe: "database.session-cookie";
554
+ }, {
555
+ readonly id: "database.sign-in-checks-for-bots";
556
+ readonly kind: "must";
557
+ readonly text: "Outside development, verify a Turnstile token with Siteverify (success, this hostname and the sign-in action) before asking Supabase to send or re-send a sign-in code, and send no code when either Turnstile key is missing.";
558
+ readonly enforced_by: "review";
559
+ readonly probe: "database.sign-in-bot-check";
534
560
  }];
535
561
  readonly examples: readonly [{
536
562
  readonly id: "database.example.user-client";
@@ -600,6 +626,12 @@ export declare const capabilities: {
600
626
  readonly expect: "pass";
601
627
  readonly cost_hint_usd: 0;
602
628
  readonly note: "The session cookie is __Host-, Secure, HttpOnly, SameSite=Lax and sealed; a cross-site write is refused; sign-out clears it with every attribute";
629
+ }, {
630
+ readonly id: "database.sign-in-bot-check";
631
+ readonly half: "drill";
632
+ readonly expect: "pass";
633
+ readonly cost_hint_usd: 0;
634
+ readonly note: "On a project's staging: cf_turnstile_widget_create and the turnstile_sitekey and turnstile_secret sources; the sign-in page shows the check, /auth/code without a passed token sends no code, and with one it does";
603
635
  }];
604
636
  };
605
637
  readonly email: {
@@ -1,6 +1,6 @@
1
1
  // Generated by `npm run capabilities:build` from capabilities/*.json. Do not edit.
2
2
  // check:capabilities fails in Checks when this file is stale.
3
- export const MANIFEST_VERSION = "ecc54c728515";
3
+ export const MANIFEST_VERSION = "7d046814165b";
4
4
  export const capabilities = {
5
5
  "ai": {
6
6
  "$schema": "./schema.json",
@@ -621,7 +621,9 @@ export const capabilities = {
621
621
  "sb_query",
622
622
  "sb_project_delete",
623
623
  "cf_worker_secret_put",
624
- "vendor_settings_apply"
624
+ "vendor_settings_apply",
625
+ "cf_turnstile_widget_create",
626
+ "cf_turnstile_widget_delete"
625
627
  ],
626
628
  "package": [
627
629
  "supabaseConfig",
@@ -678,6 +680,28 @@ export const capabilities = {
678
680
  "production"
679
681
  ],
680
682
  "description": "Seals the sign-in session cookie (createSessions). 32 random bytes written by cf_worker_secret_put source=generate:32; replacing it signs everybody out, so it is two-step. Only needed by an app with sign-in"
683
+ },
684
+ {
685
+ "name": "TURNSTILE_SITE_KEY",
686
+ "required": false,
687
+ "secret": false,
688
+ "environments": [
689
+ "development",
690
+ "staging",
691
+ "production"
692
+ ],
693
+ "description": "The public site key of the hostname's Turnstile widget, for the sign-in bot check; written by cf_worker_secret_put source=turnstile_sitekey after cf_turnstile_widget_create. Outside development, sign-in won't send codes without it"
694
+ },
695
+ {
696
+ "name": "TURNSTILE_SECRET_KEY",
697
+ "required": false,
698
+ "secret": true,
699
+ "environments": [
700
+ "development",
701
+ "staging",
702
+ "production"
703
+ ],
704
+ "description": "The secret of the hostname's Turnstile widget, sent only to Cloudflare's Siteverify; written by cf_worker_secret_put source=turnstile_secret. Outside development, sign-in won't send codes without it"
681
705
  }
682
706
  ],
683
707
  "actions": [
@@ -712,7 +736,7 @@ export const capabilities = {
712
736
  {
713
737
  "tool": "cf_worker_secret_put",
714
738
  "gate": "two_step_when",
715
- "when": "source supabase_secret, or replacing a secret that exists",
739
+ "when": "source supabase_secret, or replacing a secret that exists (not sources web_analytics, turnstile_sitekey or turnstile_secret, whose value comes from the recorded resource)",
716
740
  "ships": "4"
717
741
  },
718
742
  {
@@ -720,6 +744,16 @@ export const capabilities = {
720
744
  "gate": "two_step_when",
721
745
  "when": "production, after the first successful apply on that database; staging and check_only are free",
722
746
  "ships": "5"
747
+ },
748
+ {
749
+ "tool": "cf_turnstile_widget_create",
750
+ "gate": "free",
751
+ "ships": "5"
752
+ },
753
+ {
754
+ "tool": "cf_turnstile_widget_delete",
755
+ "gate": "two_step",
756
+ "ships": "5"
723
757
  }
724
758
  ],
725
759
  "rules": [
@@ -778,6 +812,13 @@ export const capabilities = {
778
812
  "text": "Refuse a write (anything but GET or HEAD) made with the session cookie unless sameOrigin(request) is true.",
779
813
  "enforced_by": "review",
780
814
  "probe": "database.session-cookie"
815
+ },
816
+ {
817
+ "id": "database.sign-in-checks-for-bots",
818
+ "kind": "must",
819
+ "text": "Outside development, verify a Turnstile token with Siteverify (success, this hostname and the sign-in action) before asking Supabase to send or re-send a sign-in code, and send no code when either Turnstile key is missing.",
820
+ "enforced_by": "review",
821
+ "probe": "database.sign-in-bot-check"
781
822
  }
782
823
  ],
783
824
  "examples": [
@@ -860,6 +901,13 @@ export const capabilities = {
860
901
  "expect": "pass",
861
902
  "cost_hint_usd": 0,
862
903
  "note": "The session cookie is __Host-, Secure, HttpOnly, SameSite=Lax and sealed; a cross-site write is refused; sign-out clears it with every attribute"
904
+ },
905
+ {
906
+ "id": "database.sign-in-bot-check",
907
+ "half": "drill",
908
+ "expect": "pass",
909
+ "cost_hint_usd": 0,
910
+ "note": "On a project's staging: cf_turnstile_widget_create and the turnstile_sitekey and turnstile_secret sources; the sign-in page shows the check, /auth/code without a passed token sends no code, and with one it does"
863
911
  }
864
912
  ]
865
913
  },
@@ -87,6 +87,26 @@ export const VENDOR_SETTINGS = Object.freeze([
87
87
  where: "Supabase: Authentication, Sign In / Providers, Email, Secure email change",
88
88
  breaks: "Off: an address change is confirmed from the new address only, so the owner of the old one never hears of it.",
89
89
  },
90
+ {
91
+ id: "supabase.auth.signup_skips_email_confirm",
92
+ vendor: "supabase",
93
+ area: "auth",
94
+ field: "mailer_autoconfirm",
95
+ type: "boolean",
96
+ value: false,
97
+ where: "Supabase: Authentication, Sign In / Providers, Email, Confirm email (on means this row is false)",
98
+ breaks: "On: anyone with the publishable key can sign up as any address without owning it. An app that trusts the email in the session (the template's admin claim, invitations) then hands that address's rights to a stranger.",
99
+ },
100
+ {
101
+ id: "supabase.auth.anonymous_sign_ins",
102
+ vendor: "supabase",
103
+ area: "auth",
104
+ field: "external_anonymous_users_enabled",
105
+ type: "boolean",
106
+ value: false,
107
+ where: "Supabase: Authentication, Sign In / Providers, Allow anonymous sign-ins",
108
+ breaks: "On: anyone with the publishable key gets a signed-in session with no address at all, and can then attach an address it doesn't own. Every \"signed in\" check in the app lets them through.",
109
+ },
90
110
  ]);
91
111
  const override = z.strictObject({
92
112
  id: z.string().min(1).max(100),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mccaskie-labs/workbench-config",
3
- "version": "0.1.24",
3
+ "version": "0.1.26",
4
4
  "description": "Workbench app configuration: WORKBENCH_ENV, typed variables that fail by name, secrets that are never printed, and the capabilities manifest.",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",