sealcode 1.3.3 → 1.3.5

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/cli-grants.js +61 -6
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sealcode",
3
- "version": "1.3.3",
3
+ "version": "1.3.5",
4
4
  "description": "Lock your source code in your own git repo. Stop AI agents, scrapers, and curious eyes from reading what's yours.",
5
5
  "keywords": [
6
6
  "encryption",
package/src/cli-grants.js CHANGED
@@ -706,12 +706,67 @@ async function runLockdown({ projectRoot, confirm = true } = {}) {
706
706
  return;
707
707
  }
708
708
  }
709
- const res = await request('POST', `/api/v1/projects/${linked.projectId}/lockdown`, {
710
- auth: true,
711
- body: {},
712
- });
713
- ui.ok(`Lockdown complete revoked ${ui.c.bold(res.revokedCount)} grant(s).`);
714
- if (res.revokedCount > 0) {
709
+ // sealcode@1.3.3 the server's bulk /lockdown endpoint silently 307s to
710
+ // /login for reasons that don't reproduce on any other CLI route — even
711
+ // a no-op handler stub gets intercepted. Until that's root-caused on the
712
+ // server, fall back to client-side iteration: list grants, revoke each
713
+ // active one individually. Each /revoke call works correctly and fires
714
+ // the same publishGrantLock event the bulk endpoint would have. The
715
+ // per-grant calls are issued in parallel so the wall-clock cost of a
716
+ // 20-grant lockdown is still ~1 round-trip plus the slowest revoke.
717
+ let bulkRevoked = null;
718
+ try {
719
+ const bulk = await request('POST', `/api/v1/projects/${linked.projectId}/lockdown`, {
720
+ auth: true,
721
+ body: {},
722
+ });
723
+ if (typeof bulk.revokedCount === 'number') {
724
+ bulkRevoked = bulk.revokedCount;
725
+ }
726
+ } catch (_) {
727
+ // fall through to per-grant fallback below
728
+ }
729
+
730
+ if (bulkRevoked === null) {
731
+ // Fallback: enumerate active grants and revoke them one by one.
732
+ const list = await request(
733
+ 'GET',
734
+ `/api/v1/projects/${linked.projectId}/grants?status=active,paused&limit=200`,
735
+ { auth: true },
736
+ );
737
+ const grants = Array.isArray(list.grants) ? list.grants : [];
738
+ // The serialized payload uses `state` (not `status`) — values are
739
+ // computed by describeGrant() and include "active", "paused",
740
+ // "expired", "revoked", "pending".
741
+ const live = grants.filter((g) => g.state === 'active' || g.state === 'paused');
742
+ if (live.length === 0) {
743
+ ui.ok('Lockdown complete — no active grants to revoke.');
744
+ return;
745
+ }
746
+ const results = await Promise.allSettled(
747
+ live.map((g) =>
748
+ request('DELETE', `/api/v1/grants/${encodeURIComponent(g.id)}`, { auth: true }),
749
+ ),
750
+ );
751
+ const ok = results.filter((r) => r.status === 'fulfilled').length;
752
+ const fail = results.length - ok;
753
+ if (fail > 0) {
754
+ ui.warn(`Revoked ${ok}/${live.length} grants — ${fail} failed.`);
755
+ for (const r of results) {
756
+ if (r.status === 'rejected') {
757
+ ui.fail(` - ${r.reason && r.reason.message ? r.reason.message : String(r.reason)}`);
758
+ }
759
+ }
760
+ }
761
+ ui.ok(`Lockdown complete — revoked ${ui.c.bold(ok)} grant(s).`);
762
+ if (ok > 0) {
763
+ ui.hint(' All connected watchers will re-lock within ~1 second.');
764
+ }
765
+ return;
766
+ }
767
+
768
+ ui.ok(`Lockdown complete — revoked ${ui.c.bold(bulkRevoked)} grant(s).`);
769
+ if (bulkRevoked > 0) {
715
770
  ui.hint(' All connected watchers will re-lock within ~1 second.');
716
771
  }
717
772
  }