@lanes-sh/link 0.6.6 → 0.6.8
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/package.json
CHANGED
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
openTarget,
|
|
7
7
|
readRegistry,
|
|
8
8
|
resolveWorkspaceRoot,
|
|
9
|
+
type ResolvedTarget,
|
|
9
10
|
type WorkspaceTarget,
|
|
10
11
|
} from '#profile';
|
|
11
12
|
import { ConfigError } from '#profile';
|
|
@@ -182,6 +183,27 @@ function summarise(name: string, entry: WorkspaceTarget, isSelected: boolean): T
|
|
|
182
183
|
};
|
|
183
184
|
}
|
|
184
185
|
|
|
186
|
+
/**
|
|
187
|
+
* The entry `show` renders: the declaration on the far end, plus the deploy record.
|
|
188
|
+
*
|
|
189
|
+
* **Without the `workspace:` key**, and that is the whole of it. `openTarget`
|
|
190
|
+
* merges the local pointer over the remote declaration so a redeploy from a
|
|
191
|
+
* second machine does not lose the first one's record — which leaves an entry
|
|
192
|
+
* carrying `workspace:` *and* adapters, and `isPointer` answers yes to anything
|
|
193
|
+
* with a `workspace:`. So `summarise` took the pointer branch and returned nulls
|
|
194
|
+
* for every adapter and `deployed: false`, and `target show cloud` said "No
|
|
195
|
+
* deployment — this target runs wherever the CLI does" about a target with a
|
|
196
|
+
* live Cloud Run service in front of it.
|
|
197
|
+
*
|
|
198
|
+
* This is the command that *follows* the pointer, so the pointer is the one
|
|
199
|
+
* thing it is not reporting: `resolved.workspaceRoot` is already printed on the
|
|
200
|
+
* line above, from the same object.
|
|
201
|
+
*/
|
|
202
|
+
export function resolvedEntry(resolved: ResolvedTarget): WorkspaceTarget {
|
|
203
|
+
const { workspace: _followed, ...record } = resolved.entry;
|
|
204
|
+
return { ...resolved.declared, ...record };
|
|
205
|
+
}
|
|
206
|
+
|
|
185
207
|
/** What `--json` and the tests want, without the rendering. */
|
|
186
208
|
export async function readTargets(
|
|
187
209
|
flags: TargetFlags,
|
|
@@ -310,7 +332,7 @@ export async function targetShow(name: string | undefined, flags: TargetFlags):
|
|
|
310
332
|
}
|
|
311
333
|
|
|
312
334
|
const resolved = await openTarget(root, wanted);
|
|
313
|
-
const summary = summarise(wanted,
|
|
335
|
+
const summary = summarise(wanted, resolvedEntry(resolved), true);
|
|
314
336
|
const profiles = await listProfiles(resolved.workspaceRoot);
|
|
315
337
|
|
|
316
338
|
const url = summary.deployment
|
|
@@ -50,6 +50,31 @@ export function bucketGrants(bucket: string, profiles: readonly string[]): Condi
|
|
|
50
50
|
`resource.name.startsWith("projects/_/buckets/${bucket}/objects/${path}")`;
|
|
51
51
|
const objectIs = (path: string): string =>
|
|
52
52
|
`resource.name == "projects/_/buckets/${bucket}/objects/${path}"`;
|
|
53
|
+
/**
|
|
54
|
+
* The bucket itself, which is a different resource from anything in it.
|
|
55
|
+
*
|
|
56
|
+
* **`storage.objects.list` is checked against the bucket, never against an
|
|
57
|
+
* object**, so no condition written in terms of `objects/…` can ever grant it
|
|
58
|
+
* — including a prefixed listing, which is one call with a filter rather than
|
|
59
|
+
* a walk of matching resources. Google says so outright: IAM conditions cannot
|
|
60
|
+
* restrict listing by prefix.
|
|
61
|
+
*
|
|
62
|
+
* This was invisible until the day the narrowing actually applied. The
|
|
63
|
+
* `reads-its-config` binding had been sitting at `expression=true` since the
|
|
64
|
+
* first deploy, and `true` matches the bucket resource as readily as an object
|
|
65
|
+
* — so listing worked, and every deploy that thought it had replaced that
|
|
66
|
+
* binding had in fact only added one beside it. The first deploy that removed
|
|
67
|
+
* the old one rolled a revision that could not list its own workspace, exited
|
|
68
|
+
* 1, and took the endpoint's listing with it: `objects.list` had never been
|
|
69
|
+
* granted by anything else.
|
|
70
|
+
*
|
|
71
|
+
* Only `storage.objects.list` can come of it. Every other permission in
|
|
72
|
+
* `objectViewer` is either evaluated against an object — where the prefixes
|
|
73
|
+
* below still decide — or is a project-level permission a binding on a bucket
|
|
74
|
+
* does not reach. So the concession is the names of the objects in this
|
|
75
|
+
* bucket, and reads stay scoped to the config.
|
|
76
|
+
*/
|
|
77
|
+
const theBucket = `resource.name == "projects/_/buckets/${bucket}"`;
|
|
53
78
|
|
|
54
79
|
const manifestPrefixes = profiles.map((profile) =>
|
|
55
80
|
objectsUnder(`${layout.providers(profile)}/`),
|
|
@@ -73,7 +98,7 @@ export function bucketGrants(bucket: string, profiles: readonly string[]): Condi
|
|
|
73
98
|
// and each profile's own manifests, so name exactly those.
|
|
74
99
|
role: 'roles/storage.objectViewer',
|
|
75
100
|
title: 'reads-its-config',
|
|
76
|
-
expression: `${objectsUnder('profiles/')} || ${objectIs('lanes-link.yaml')}${manifests ? ` || ${manifests}` : ''}`,
|
|
101
|
+
expression: `${theBucket} || ${objectsUnder('profiles/')} || ${objectIs('lanes-link.yaml')}${manifests ? ` || ${manifests}` : ''}`,
|
|
77
102
|
},
|
|
78
103
|
];
|
|
79
104
|
}
|
|
@@ -108,6 +133,17 @@ export async function bucketSteps(input: {
|
|
|
108
133
|
// served publicly; uniform access removes per-object ACLs as a way to
|
|
109
134
|
// get that wrong.
|
|
110
135
|
'--uniform-bucket-level-access',
|
|
136
|
+
// Autoclass rather than a lifecycle rule, because no one fixed class is
|
|
137
|
+
// right for this bucket: it holds the config the endpoint reads on every
|
|
138
|
+
// boot next to assets and audit rows nobody opens again. Inside an
|
|
139
|
+
// Autoclass bucket there are no retrieval and no early-deletion fees,
|
|
140
|
+
// which is what makes ARCHIVE safe as the floor rather than a bet on
|
|
141
|
+
// never reading the thing again — a read pulls the object back to
|
|
142
|
+
// Standard at no charge. Objects under 128 KiB never leave Standard, so
|
|
143
|
+
// this costs the config and the log nothing and saves on attachments.
|
|
144
|
+
'--enable-autoclass',
|
|
145
|
+
'--autoclass-terminal-storage-class',
|
|
146
|
+
'ARCHIVE',
|
|
111
147
|
],
|
|
112
148
|
tolerateFailure: true,
|
|
113
149
|
},
|