@runveric/cli 0.1.2 → 0.2.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 +29 -3
- package/dist/runveric.mjs +1188 -144
- package/dist/runveric.mjs.map +1 -1
- package/package.json +2 -2
package/dist/runveric.mjs
CHANGED
|
@@ -212,13 +212,17 @@ var require_wire_identity = __commonJS({
|
|
|
212
212
|
Object.defineProperty(exports, "__esModule", {
|
|
213
213
|
value: true
|
|
214
214
|
});
|
|
215
|
-
exports.PROBLEM_TYPE_BASE = exports.RUNNER_PROTOCOL_VERSION = exports.PACKAGE_WORK_ITEM_VERSION = exports.ACTION_MANIFEST_API_VERSION = exports.PACKAGE_EXECUTION_PROTOCOL_VERSION = exports.PACKAGE_RESULT_PROTOCOL_VERSION = void 0;
|
|
215
|
+
exports.PROBLEM_TYPE_BASE = exports.CATALOG_ARTIFACT_MEDIA_TYPE = exports.CATALOG_ACTION_ARTIFACT_SCHEMA_V1 = exports.CATALOG_RELEASE_SCHEMA_V1 = exports.EVIDENCE_PACK_SCHEMA_VERSION = exports.RUNNER_PROTOCOL_VERSION = exports.PACKAGE_WORK_ITEM_VERSION = exports.ACTION_MANIFEST_API_VERSION = exports.PACKAGE_EXECUTION_PROTOCOL_VERSION = exports.PACKAGE_RESULT_PROTOCOL_VERSION = void 0;
|
|
216
216
|
exports.problemType = problemType;
|
|
217
217
|
exports.PACKAGE_RESULT_PROTOCOL_VERSION = "runveric.dev/package-result/v1";
|
|
218
218
|
exports.PACKAGE_EXECUTION_PROTOCOL_VERSION = "runveric.dev/package-execution/v1";
|
|
219
219
|
exports.ACTION_MANIFEST_API_VERSION = "runveric.dev/action/v1";
|
|
220
220
|
exports.PACKAGE_WORK_ITEM_VERSION = "runveric.dev/package-work-item/v1";
|
|
221
221
|
exports.RUNNER_PROTOCOL_VERSION = "runveric.dev/runner-channel/v2";
|
|
222
|
+
exports.EVIDENCE_PACK_SCHEMA_VERSION = "runveric.dev/evidence-pack/v1";
|
|
223
|
+
exports.CATALOG_RELEASE_SCHEMA_V1 = "runveric.dev/catalog-release/v1";
|
|
224
|
+
exports.CATALOG_ACTION_ARTIFACT_SCHEMA_V1 = "runveric.dev/catalog-action/v1";
|
|
225
|
+
exports.CATALOG_ARTIFACT_MEDIA_TYPE = "application/vnd.runveric.catalog-artifact+json";
|
|
222
226
|
exports.PROBLEM_TYPE_BASE = "https://runveric.dev/errors";
|
|
223
227
|
function problemType(slug) {
|
|
224
228
|
return `${exports.PROBLEM_TYPE_BASE}/${slug}`;
|
|
@@ -301,6 +305,13 @@ var require_permissions = __commonJS({
|
|
|
301
305
|
Object.defineProperty(exports, "__esModule", {
|
|
302
306
|
value: true
|
|
303
307
|
});
|
|
308
|
+
exports.PLATFORM_PERMISSIONS = void 0;
|
|
309
|
+
exports.PLATFORM_PERMISSIONS = [
|
|
310
|
+
// Which catalog release is live for every workspace (docs/121). Pinning one changes what EVERY
|
|
311
|
+
// workspace can run, so it is neither `policy:manage` (one workspace's own governance) nor
|
|
312
|
+
// `catalog:read` (the right to browse).
|
|
313
|
+
"catalog:release"
|
|
314
|
+
];
|
|
304
315
|
}
|
|
305
316
|
});
|
|
306
317
|
|
|
@@ -443,6 +454,41 @@ var require_groups = __commonJS({
|
|
|
443
454
|
}
|
|
444
455
|
});
|
|
445
456
|
|
|
457
|
+
// ../contracts/dist/catalog-policy.js
|
|
458
|
+
var require_catalog_policy = __commonJS({
|
|
459
|
+
"../contracts/dist/catalog-policy.js"(exports) {
|
|
460
|
+
"use strict";
|
|
461
|
+
Object.defineProperty(exports, "__esModule", {
|
|
462
|
+
value: true
|
|
463
|
+
});
|
|
464
|
+
exports.CATALOG_RULE_EFFECTS = exports.CATALOG_DEFAULT_MODE_WHEN_UNSET = exports.CATALOG_DEFAULT_MODES = void 0;
|
|
465
|
+
exports.effectiveCatalogAccess = effectiveCatalogAccess;
|
|
466
|
+
var CATALOG_DEFAULT_MODE_SET = {
|
|
467
|
+
allow_all: true,
|
|
468
|
+
deny_all: true
|
|
469
|
+
};
|
|
470
|
+
exports.CATALOG_DEFAULT_MODES = Object.keys(CATALOG_DEFAULT_MODE_SET);
|
|
471
|
+
exports.CATALOG_DEFAULT_MODE_WHEN_UNSET = "allow_all";
|
|
472
|
+
var CATALOG_RULE_EFFECT_SET = {
|
|
473
|
+
allow: true,
|
|
474
|
+
deny: true
|
|
475
|
+
};
|
|
476
|
+
exports.CATALOG_RULE_EFFECTS = Object.keys(CATALOG_RULE_EFFECT_SET);
|
|
477
|
+
var RULE_ACCESS = {
|
|
478
|
+
allow: "allowed",
|
|
479
|
+
deny: "blocked"
|
|
480
|
+
};
|
|
481
|
+
var UNRULED_ACCESS = {
|
|
482
|
+
allow_all: "allowed",
|
|
483
|
+
deny_all: "blocked"
|
|
484
|
+
};
|
|
485
|
+
function effectiveCatalogAccess(defaultMode, rule) {
|
|
486
|
+
return rule !== null ? RULE_ACCESS[rule] : UNRULED_ACCESS[defaultMode];
|
|
487
|
+
}
|
|
488
|
+
__name(effectiveCatalogAccess, "effectiveCatalogAccess");
|
|
489
|
+
}
|
|
490
|
+
});
|
|
491
|
+
|
|
446
492
|
// ../contracts/dist/catalog.js
|
|
447
493
|
var require_catalog = __commonJS({
|
|
448
494
|
"../contracts/dist/catalog.js"(exports) {
|
|
@@ -558,6 +604,315 @@ var require_catalog = __commonJS({
|
|
|
558
604
|
}
|
|
559
605
|
});
|
|
560
606
|
|
|
607
|
+
// ../contracts/dist/catalog-release.js
|
|
608
|
+
var require_catalog_release = __commonJS({
|
|
609
|
+
"../contracts/dist/catalog-release.js"(exports) {
|
|
610
|
+
"use strict";
|
|
611
|
+
Object.defineProperty(exports, "__esModule", {
|
|
612
|
+
value: true
|
|
613
|
+
});
|
|
614
|
+
exports.ARTIFACT_DIGEST_PATTERN = exports.ARTIFACT_REPOSITORY_PATTERN = exports.CATALOG_ACTION_ARTIFACT_SCHEMA_VERSIONS = exports.CATALOG_RELEASE_SCHEMA_VERSIONS = void 0;
|
|
615
|
+
var wire_identity_1 = require_wire_identity();
|
|
616
|
+
exports.CATALOG_RELEASE_SCHEMA_VERSIONS = [
|
|
617
|
+
wire_identity_1.CATALOG_RELEASE_SCHEMA_V1
|
|
618
|
+
];
|
|
619
|
+
exports.CATALOG_ACTION_ARTIFACT_SCHEMA_VERSIONS = [
|
|
620
|
+
wire_identity_1.CATALOG_ACTION_ARTIFACT_SCHEMA_V1
|
|
621
|
+
];
|
|
622
|
+
exports.ARTIFACT_REPOSITORY_PATTERN = /^[a-z0-9][a-z0-9.-]*(:[0-9]+)?(\/[a-z0-9][a-z0-9._-]*)+$/;
|
|
623
|
+
exports.ARTIFACT_DIGEST_PATTERN = /^sha256:[0-9a-f]{64}$/;
|
|
624
|
+
}
|
|
625
|
+
});
|
|
626
|
+
|
|
627
|
+
// ../contracts/dist/action-repository.js
|
|
628
|
+
var require_action_repository = __commonJS({
|
|
629
|
+
"../contracts/dist/action-repository.js"(exports) {
|
|
630
|
+
"use strict";
|
|
631
|
+
Object.defineProperty(exports, "__esModule", {
|
|
632
|
+
value: true
|
|
633
|
+
});
|
|
634
|
+
exports.ACTION_REPOSITORY_PREFIX = void 0;
|
|
635
|
+
exports.actionKeyRefusal = actionKeyRefusal;
|
|
636
|
+
exports.isActionKey = isActionKey;
|
|
637
|
+
exports.actionRepositoryName = actionRepositoryName;
|
|
638
|
+
exports.actionKeyOf = actionKeyOf;
|
|
639
|
+
exports.actionPackageRefusal = actionPackageRefusal3;
|
|
640
|
+
exports.ACTION_REPOSITORY_PREFIX = "action-";
|
|
641
|
+
var WORD = /^[a-z][a-z0-9]*$/;
|
|
642
|
+
var VERB = /^[a-z][a-z0-9]*(?:[A-Z][a-z0-9]+)*$/;
|
|
643
|
+
function actionKeyRefusal(key) {
|
|
644
|
+
const shape = "an action key is <provider>.<resource>.<verb>: provider and resource are one lowercase word (a-z, then a-z or 0-9), the verb is camelCase with no two capitals in a row \u2014 so the key maps to exactly one repository name and back.";
|
|
645
|
+
const segments = key.split(".");
|
|
646
|
+
if (segments.length !== 3) {
|
|
647
|
+
return `"${key}" is not an action key: it has ${segments.length} dot-separated segment(s), not 3; ${shape}`;
|
|
648
|
+
}
|
|
649
|
+
const [provider, resource, verb] = segments;
|
|
650
|
+
const not = /* @__PURE__ */ __name((what) => `"${key}" is not an action key: ${what}; ${shape}`, "not");
|
|
651
|
+
if (!WORD.test(provider)) return not(`its provider "${provider}" is not one lowercase word`);
|
|
652
|
+
if (!WORD.test(resource)) return not(`its resource "${resource}" is not one lowercase word`);
|
|
653
|
+
if (!VERB.test(verb)) return not(`its verb "${verb}" is not camelCase without two capitals in a row`);
|
|
654
|
+
return null;
|
|
655
|
+
}
|
|
656
|
+
__name(actionKeyRefusal, "actionKeyRefusal");
|
|
657
|
+
function isActionKey(key) {
|
|
658
|
+
return actionKeyRefusal(key) === null;
|
|
659
|
+
}
|
|
660
|
+
__name(isActionKey, "isActionKey");
|
|
661
|
+
var kebab = /* @__PURE__ */ __name((verb) => verb.replace(/[A-Z]/g, (capital) => `-${capital.toLowerCase()}`), "kebab");
|
|
662
|
+
function actionRepositoryName(key) {
|
|
663
|
+
const refusal = actionKeyRefusal(key);
|
|
664
|
+
if (refusal !== null) throw new Error(refusal);
|
|
665
|
+
const [provider, resource, verb] = key.split(".");
|
|
666
|
+
return `${exports.ACTION_REPOSITORY_PREFIX}${provider}-${resource}-${kebab(verb)}`;
|
|
667
|
+
}
|
|
668
|
+
__name(actionRepositoryName, "actionRepositoryName");
|
|
669
|
+
function actionKeyOf(name) {
|
|
670
|
+
if (!name.startsWith(exports.ACTION_REPOSITORY_PREFIX)) return null;
|
|
671
|
+
const [provider, resource, first2, ...rest] = name.slice(exports.ACTION_REPOSITORY_PREFIX.length).split("-");
|
|
672
|
+
if (provider === void 0 || resource === void 0 || first2 === void 0) return null;
|
|
673
|
+
const verb = first2 + rest.map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join("");
|
|
674
|
+
const key = `${provider}.${resource}.${verb}`;
|
|
675
|
+
return isActionKey(key) && actionRepositoryName(key) === name ? key : null;
|
|
676
|
+
}
|
|
677
|
+
__name(actionKeyOf, "actionKeyOf");
|
|
678
|
+
function actionPackageRefusal3(key, artifactRef) {
|
|
679
|
+
const keyRefusal = actionKeyRefusal(key);
|
|
680
|
+
if (keyRefusal !== null) return `${keyRefusal} No package can carry it.`;
|
|
681
|
+
const cut = artifactRef.lastIndexOf("/");
|
|
682
|
+
const named = artifactRef.slice(cut + 1);
|
|
683
|
+
const expected = actionRepositoryName(key);
|
|
684
|
+
if (named === expected) return null;
|
|
685
|
+
return `action "${key}" is published only from a package named "${expected}" (${artifactRef.slice(0, cut + 1)}${expected}), not "${named}". An action's package carries its key's name, so an artifact cannot claim an identity its package does not carry.`;
|
|
686
|
+
}
|
|
687
|
+
__name(actionPackageRefusal3, "actionPackageRefusal");
|
|
688
|
+
}
|
|
689
|
+
});
|
|
690
|
+
|
|
691
|
+
// ../contracts/dist/catalog-release-spec.js
|
|
692
|
+
var require_catalog_release_spec = __commonJS({
|
|
693
|
+
"../contracts/dist/catalog-release-spec.js"(exports) {
|
|
694
|
+
"use strict";
|
|
695
|
+
Object.defineProperty(exports, "__esModule", {
|
|
696
|
+
value: true
|
|
697
|
+
});
|
|
698
|
+
exports.CatalogReleaseSpecError = void 0;
|
|
699
|
+
exports.splitArtifactReference = splitArtifactReference;
|
|
700
|
+
exports.parseCatalogReleaseSpec = parseCatalogReleaseSpec2;
|
|
701
|
+
var CatalogReleaseSpecError = class CatalogReleaseSpecError extends Error {
|
|
702
|
+
static {
|
|
703
|
+
__name(this, "CatalogReleaseSpecError");
|
|
704
|
+
}
|
|
705
|
+
constructor(message) {
|
|
706
|
+
super(message);
|
|
707
|
+
this.name = "CatalogReleaseSpecError";
|
|
708
|
+
}
|
|
709
|
+
};
|
|
710
|
+
exports.CatalogReleaseSpecError = CatalogReleaseSpecError;
|
|
711
|
+
function splitArtifactReference(reference) {
|
|
712
|
+
const at = reference.indexOf("@");
|
|
713
|
+
if (at <= 0 || at === reference.length - 1) return null;
|
|
714
|
+
return {
|
|
715
|
+
artifactRef: reference.slice(0, at),
|
|
716
|
+
digest: reference.slice(at + 1)
|
|
717
|
+
};
|
|
718
|
+
}
|
|
719
|
+
__name(splitArtifactReference, "splitArtifactReference");
|
|
720
|
+
var isMapping2 = /* @__PURE__ */ __name((value) => typeof value === "object" && value !== null && !Array.isArray(value), "isMapping");
|
|
721
|
+
function parseCatalogReleaseSpec2(value) {
|
|
722
|
+
if (!isMapping2(value)) {
|
|
723
|
+
throw new CatalogReleaseSpecError("release.yaml is not a mapping of `version` and `actions`.");
|
|
724
|
+
}
|
|
725
|
+
const unknown = Object.keys(value).filter((key) => key !== "version" && key !== "actions");
|
|
726
|
+
if (unknown.length > 0) {
|
|
727
|
+
throw new CatalogReleaseSpecError(`release.yaml carries ${unknown.map((key) => `"${key}"`).join(", ")}; it has exactly two fields, \`version\` and \`actions\`.`);
|
|
728
|
+
}
|
|
729
|
+
const { version: version2, actions } = value;
|
|
730
|
+
if (typeof version2 !== "string" || version2.trim().length === 0) {
|
|
731
|
+
throw new CatalogReleaseSpecError(`release.yaml's version is ${JSON.stringify(version2 ?? null)}, not a label. Write it as a quoted string \u2014 version: "2026.10.1" \u2014 because YAML reads an unquoted 2026.10 as a number.`);
|
|
732
|
+
}
|
|
733
|
+
if (actions === null || actions === void 0 || isMapping2(actions) && Object.keys(actions).length === 0) {
|
|
734
|
+
throw new CatalogReleaseSpecError("release.yaml declares no action. An empty release is refused: pinned, it would declare a catalog with nothing in it.");
|
|
735
|
+
}
|
|
736
|
+
if (!isMapping2(actions)) {
|
|
737
|
+
throw new CatalogReleaseSpecError("release.yaml's actions is not a mapping of action key to <repository>@<digest>.");
|
|
738
|
+
}
|
|
739
|
+
return {
|
|
740
|
+
version: version2,
|
|
741
|
+
actions: Object.entries(actions).map(([key, reference]) => {
|
|
742
|
+
const split = typeof reference === "string" ? splitArtifactReference(reference) : null;
|
|
743
|
+
if (split === null) {
|
|
744
|
+
throw new CatalogReleaseSpecError(`release.yaml's ${key} is ${JSON.stringify(reference)}, not <repository>@<digest>.`);
|
|
745
|
+
}
|
|
746
|
+
return {
|
|
747
|
+
key,
|
|
748
|
+
...split
|
|
749
|
+
};
|
|
750
|
+
})
|
|
751
|
+
};
|
|
752
|
+
}
|
|
753
|
+
__name(parseCatalogReleaseSpec2, "parseCatalogReleaseSpec");
|
|
754
|
+
}
|
|
755
|
+
});
|
|
756
|
+
|
|
757
|
+
// ../contracts/dist/catalog-lock.js
|
|
758
|
+
var require_catalog_lock = __commonJS({
|
|
759
|
+
"../contracts/dist/catalog-lock.js"(exports) {
|
|
760
|
+
"use strict";
|
|
761
|
+
Object.defineProperty(exports, "__esModule", {
|
|
762
|
+
value: true
|
|
763
|
+
});
|
|
764
|
+
exports.CatalogLockError = exports.CATALOG_LOCK_FILE = exports.CATALOG_LOCK_SCHEMA_V1 = void 0;
|
|
765
|
+
exports.parseCatalogLock = parseCatalogLock;
|
|
766
|
+
exports.catalogLockText = catalogLockText;
|
|
767
|
+
exports.authoredElsewhere = authoredElsewhere;
|
|
768
|
+
var action_repository_1 = require_action_repository();
|
|
769
|
+
var catalog_release_1 = require_catalog_release();
|
|
770
|
+
exports.CATALOG_LOCK_SCHEMA_V1 = "runveric.catalog-lock/v1";
|
|
771
|
+
exports.CATALOG_LOCK_FILE = "release.lock.json";
|
|
772
|
+
var CatalogLockError = class CatalogLockError extends Error {
|
|
773
|
+
static {
|
|
774
|
+
__name(this, "CatalogLockError");
|
|
775
|
+
}
|
|
776
|
+
constructor(message) {
|
|
777
|
+
super(message);
|
|
778
|
+
this.name = "CatalogLockError";
|
|
779
|
+
}
|
|
780
|
+
};
|
|
781
|
+
exports.CatalogLockError = CatalogLockError;
|
|
782
|
+
var SHA256_HEX = /^[0-9a-f]{64}$/;
|
|
783
|
+
function objectAt(path, value, keys) {
|
|
784
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
785
|
+
throw new CatalogLockError(`${path} is not an object.`);
|
|
786
|
+
}
|
|
787
|
+
const unknown = Object.keys(value).filter((key) => !keys.includes(key));
|
|
788
|
+
if (unknown.length > 0) {
|
|
789
|
+
throw new CatalogLockError(`${path} carries ${unknown.map((key) => `"${key}"`).join(", ")}, which a lock does not have. A lock is written by catalog:vendor and never edited; re-vendor instead.`);
|
|
790
|
+
}
|
|
791
|
+
return value;
|
|
792
|
+
}
|
|
793
|
+
__name(objectAt, "objectAt");
|
|
794
|
+
function stringAt(path, value, pattern, expected) {
|
|
795
|
+
if (typeof value !== "string" || value.length === 0) {
|
|
796
|
+
throw new CatalogLockError(`${path} is not a non-empty string.`);
|
|
797
|
+
}
|
|
798
|
+
if (pattern !== void 0 && !pattern.test(value)) {
|
|
799
|
+
throw new CatalogLockError(`${path} is "${value}", which is not ${expected}.`);
|
|
800
|
+
}
|
|
801
|
+
return value;
|
|
802
|
+
}
|
|
803
|
+
__name(stringAt, "stringAt");
|
|
804
|
+
function parseCatalogLock(value) {
|
|
805
|
+
const root = objectAt("the lock", value, [
|
|
806
|
+
"schemaVersion",
|
|
807
|
+
"release",
|
|
808
|
+
"actions"
|
|
809
|
+
]);
|
|
810
|
+
if (root.schemaVersion !== exports.CATALOG_LOCK_SCHEMA_V1) {
|
|
811
|
+
throw new CatalogLockError(`the lock declares schemaVersion ${JSON.stringify(root.schemaVersion)}; this build reads ${exports.CATALOG_LOCK_SCHEMA_V1} only.`);
|
|
812
|
+
}
|
|
813
|
+
const release = objectAt("release", root.release, [
|
|
814
|
+
"artifactRef",
|
|
815
|
+
"digest",
|
|
816
|
+
"version"
|
|
817
|
+
]);
|
|
818
|
+
const lock = {
|
|
819
|
+
schemaVersion: exports.CATALOG_LOCK_SCHEMA_V1,
|
|
820
|
+
release: {
|
|
821
|
+
artifactRef: stringAt("release.artifactRef", release.artifactRef, catalog_release_1.ARTIFACT_REPOSITORY_PATTERN, "a registry repository"),
|
|
822
|
+
digest: stringAt("release.digest", release.digest, catalog_release_1.ARTIFACT_DIGEST_PATTERN, "a sha256 digest"),
|
|
823
|
+
version: stringAt("release.version", release.version)
|
|
824
|
+
},
|
|
825
|
+
actions: []
|
|
826
|
+
};
|
|
827
|
+
if (!Array.isArray(root.actions) || root.actions.length === 0) {
|
|
828
|
+
throw new CatalogLockError("actions is not a non-empty array. A release names at least one action.");
|
|
829
|
+
}
|
|
830
|
+
root.actions.forEach((entry, index) => {
|
|
831
|
+
const path = `actions[${index}]`;
|
|
832
|
+
const action = objectAt(path, entry, [
|
|
833
|
+
"key",
|
|
834
|
+
"artifactRef",
|
|
835
|
+
"digest",
|
|
836
|
+
"manifestSha256",
|
|
837
|
+
"provenance"
|
|
838
|
+
]);
|
|
839
|
+
const key = stringAt(`${path}.key`, action.key);
|
|
840
|
+
const artifactRef = stringAt(`${path}.artifactRef`, action.artifactRef, catalog_release_1.ARTIFACT_REPOSITORY_PATTERN, "a registry repository");
|
|
841
|
+
const misnamed = (0, action_repository_1.actionPackageRefusal)(key, artifactRef);
|
|
842
|
+
if (misnamed !== null) throw new CatalogLockError(`${path}: ${misnamed}`);
|
|
843
|
+
const previous = lock.actions[lock.actions.length - 1];
|
|
844
|
+
if (previous !== void 0 && !(previous.key < key)) {
|
|
845
|
+
throw new CatalogLockError(`${path}.key "${key}" follows "${previous.key}": a lock names each action once, sorted by key.`);
|
|
846
|
+
}
|
|
847
|
+
const provenance2 = objectAt(`${path}.provenance`, action.provenance, [
|
|
848
|
+
"repository",
|
|
849
|
+
"commit"
|
|
850
|
+
]);
|
|
851
|
+
lock.actions.push({
|
|
852
|
+
key,
|
|
853
|
+
artifactRef,
|
|
854
|
+
digest: stringAt(`${path}.digest`, action.digest, catalog_release_1.ARTIFACT_DIGEST_PATTERN, "a sha256 digest"),
|
|
855
|
+
manifestSha256: stringAt(`${path}.manifestSha256`, action.manifestSha256, SHA256_HEX, "64 lowercase hex characters"),
|
|
856
|
+
provenance: {
|
|
857
|
+
repository: stringAt(`${path}.provenance.repository`, provenance2.repository),
|
|
858
|
+
commit: stringAt(`${path}.provenance.commit`, provenance2.commit)
|
|
859
|
+
}
|
|
860
|
+
});
|
|
861
|
+
});
|
|
862
|
+
return lock;
|
|
863
|
+
}
|
|
864
|
+
__name(parseCatalogLock, "parseCatalogLock");
|
|
865
|
+
function catalogLockText(lock) {
|
|
866
|
+
const ordered = {
|
|
867
|
+
schemaVersion: lock.schemaVersion,
|
|
868
|
+
release: {
|
|
869
|
+
artifactRef: lock.release.artifactRef,
|
|
870
|
+
digest: lock.release.digest,
|
|
871
|
+
version: lock.release.version
|
|
872
|
+
},
|
|
873
|
+
actions: [
|
|
874
|
+
...lock.actions
|
|
875
|
+
].sort((a, b) => a.key < b.key ? -1 : a.key > b.key ? 1 : 0).map((action) => ({
|
|
876
|
+
key: action.key,
|
|
877
|
+
artifactRef: action.artifactRef,
|
|
878
|
+
digest: action.digest,
|
|
879
|
+
manifestSha256: action.manifestSha256,
|
|
880
|
+
provenance: {
|
|
881
|
+
repository: action.provenance.repository,
|
|
882
|
+
commit: action.provenance.commit
|
|
883
|
+
}
|
|
884
|
+
}))
|
|
885
|
+
};
|
|
886
|
+
return `${JSON.stringify(ordered, null, 2)}
|
|
887
|
+
`;
|
|
888
|
+
}
|
|
889
|
+
__name(catalogLockText, "catalogLockText");
|
|
890
|
+
function authoredElsewhere(lock, key) {
|
|
891
|
+
const namespace = lock.release.artifactRef.slice(0, lock.release.artifactRef.lastIndexOf("/"));
|
|
892
|
+
const organisation = namespace.slice(namespace.lastIndexOf("/") + 1);
|
|
893
|
+
return `${key} is authored in ${organisation}/${(0, action_repository_1.actionRepositoryName)(key)} \u2014 change it there, publish, assemble, vendor`;
|
|
894
|
+
}
|
|
895
|
+
__name(authoredElsewhere, "authoredElsewhere");
|
|
896
|
+
}
|
|
897
|
+
});
|
|
898
|
+
|
|
899
|
+
// ../contracts/dist/catalog-manifest-placeholders.js
|
|
900
|
+
var require_catalog_manifest_placeholders = __commonJS({
|
|
901
|
+
"../contracts/dist/catalog-manifest-placeholders.js"(exports) {
|
|
902
|
+
"use strict";
|
|
903
|
+
Object.defineProperty(exports, "__esModule", {
|
|
904
|
+
value: true
|
|
905
|
+
});
|
|
906
|
+
exports.MANIFEST_PLACEHOLDER_PATTERN = exports.MANIFEST_PLACEHOLDERS = void 0;
|
|
907
|
+
var brand_1 = require_brand();
|
|
908
|
+
exports.MANIFEST_PLACEHOLDERS = {
|
|
909
|
+
BRAND_SHORT_NAME: brand_1.BRAND_SHORT_NAME,
|
|
910
|
+
BRAND_NAME: brand_1.BRAND_NAME
|
|
911
|
+
};
|
|
912
|
+
exports.MANIFEST_PLACEHOLDER_PATTERN = /\{\{\s*([A-Za-z_][A-Za-z0-9_]*)\s*\}\}/g;
|
|
913
|
+
}
|
|
914
|
+
});
|
|
915
|
+
|
|
561
916
|
// ../contracts/dist/change-control.js
|
|
562
917
|
var require_change_control = __commonJS({
|
|
563
918
|
"../contracts/dist/change-control.js"(exports) {
|
|
@@ -857,8 +1212,8 @@ var require_package_provenance = __commonJS({
|
|
|
857
1212
|
pair.accepted,
|
|
858
1213
|
pair.revoked
|
|
859
1214
|
]);
|
|
860
|
-
function poolProvenanceAuditAction(
|
|
861
|
-
const pair = exports.POOL_PROVENANCE_AUDIT_ACTIONS[
|
|
1215
|
+
function poolProvenanceAuditAction(provenance2, accepted) {
|
|
1216
|
+
const pair = exports.POOL_PROVENANCE_AUDIT_ACTIONS[provenance2];
|
|
862
1217
|
return accepted ? pair.accepted : pair.revoked;
|
|
863
1218
|
}
|
|
864
1219
|
__name(poolProvenanceAuditAction, "poolProvenanceAuditAction");
|
|
@@ -1286,7 +1641,7 @@ var require_validation = __commonJS({
|
|
|
1286
1641
|
Object.defineProperty(exports, "__esModule", {
|
|
1287
1642
|
value: true
|
|
1288
1643
|
});
|
|
1289
|
-
exports.TARGET_COMPARISON_KINDS = exports.TARGETS_NO_SCOPE = exports.TARGETS_NOT_COUNTED = exports.TARGET_COUNT_ABSENCES = void 0;
|
|
1644
|
+
exports.TARGET_COMPARISON_KINDS = exports.DECISION_CODES = exports.REFUSAL_CODES = exports.CHECK_LEVELS = exports.TARGETS_NO_SCOPE = exports.TARGETS_NOT_COUNTED = exports.TARGET_COUNT_ABSENCES = void 0;
|
|
1290
1645
|
exports.isTargetCountAbsence = isTargetCountAbsence;
|
|
1291
1646
|
exports.singleTarget = singleTarget;
|
|
1292
1647
|
exports.noTargetsResolved = noTargetsResolved;
|
|
@@ -1296,6 +1651,9 @@ var require_validation = __commonJS({
|
|
|
1296
1651
|
exports.eligibleTargetCount = eligibleTargetCount;
|
|
1297
1652
|
exports.targetsValidationCheck = targetsValidationCheck;
|
|
1298
1653
|
exports.targetSummaryOf = targetSummaryOf;
|
|
1654
|
+
exports.isCheckLevel = isCheckLevel;
|
|
1655
|
+
exports.isRefusalCode = isRefusalCode;
|
|
1656
|
+
exports.isDecisionCode = isDecisionCode;
|
|
1299
1657
|
exports.scopeFailureDetail = scopeFailureDetail;
|
|
1300
1658
|
exports.targetsUnavailableFrom = targetsUnavailableFrom;
|
|
1301
1659
|
exports.compareTargets = compareTargets;
|
|
@@ -1412,6 +1770,38 @@ var require_validation = __commonJS({
|
|
|
1412
1770
|
return exports.TARGETS_NOT_COUNTED;
|
|
1413
1771
|
}
|
|
1414
1772
|
__name(targetSummaryOf, "targetSummaryOf");
|
|
1773
|
+
exports.CHECK_LEVELS = [
|
|
1774
|
+
"info",
|
|
1775
|
+
"warn",
|
|
1776
|
+
"error"
|
|
1777
|
+
];
|
|
1778
|
+
function isCheckLevel(value) {
|
|
1779
|
+
return typeof value === "string" && exports.CHECK_LEVELS.includes(value);
|
|
1780
|
+
}
|
|
1781
|
+
__name(isCheckLevel, "isCheckLevel");
|
|
1782
|
+
exports.REFUSAL_CODES = [
|
|
1783
|
+
"disk.notUnattached",
|
|
1784
|
+
"disk.locked",
|
|
1785
|
+
"disk.shared",
|
|
1786
|
+
"disk.inRecoveryPlan",
|
|
1787
|
+
"disk.keyUnusable",
|
|
1788
|
+
"disk.unverifiable"
|
|
1789
|
+
];
|
|
1790
|
+
function isRefusalCode(value) {
|
|
1791
|
+
return typeof value === "string" && exports.REFUSAL_CODES.includes(value);
|
|
1792
|
+
}
|
|
1793
|
+
__name(isRefusalCode, "isRefusalCode");
|
|
1794
|
+
exports.DECISION_CODES = [
|
|
1795
|
+
"disk.recentlyDetached",
|
|
1796
|
+
"disk.customerKey",
|
|
1797
|
+
"disk.customerKeyUnverified",
|
|
1798
|
+
"disk.guestEncrypted",
|
|
1799
|
+
"disk.noSnapshot"
|
|
1800
|
+
];
|
|
1801
|
+
function isDecisionCode(value) {
|
|
1802
|
+
return typeof value === "string" && exports.DECISION_CODES.includes(value);
|
|
1803
|
+
}
|
|
1804
|
+
__name(isDecisionCode, "isDecisionCode");
|
|
1415
1805
|
function scopeFailureDetail(error) {
|
|
1416
1806
|
const raw = error instanceof Error ? error.message : String(error);
|
|
1417
1807
|
const oneLine = raw.replace(/\s+/g, " ").trim().replace(/[.!]+$/, "");
|
|
@@ -1482,7 +1872,7 @@ var require_execution = __commonJS({
|
|
|
1482
1872
|
Object.defineProperty(exports, "__esModule", {
|
|
1483
1873
|
value: true
|
|
1484
1874
|
});
|
|
1485
|
-
exports.ACCEPTING_A_PROVENANCE_IS_NOT_A_CAPABILITY = exports.RUNNER_PACKAGE_RUNTIME_NOT_PINNED = exports.CONNECTOR_UNAVAILABLE_MESSAGE = exports.ACTION_RUNNABILITY_CAUSE_KINDS = exports.EXECUTION_LOG_ACTIVITY_PHRASE = exports.EXECUTION_LOG_CONNECTION_PHRASE = exports.EXECUTION_LOG_STREAM_PHASES = exports.EXECUTION_LOG_ACTIVITIES = exports.targetsValidationCheck = exports.targetSummarySentence = exports.targetSummaryOf = exports.targetSummaryLabel = exports.targetsUnavailableFrom = exports.targetsUnavailable = exports.targetComparisonSentence = exports.targetComparisonLevel = exports.targetComparisonLabel = exports.TARGETS_NOT_COUNTED = exports.TARGETS_NO_SCOPE = exports.TARGET_COUNT_ABSENCES = exports.TARGET_COMPARISON_KINDS = exports.singleTarget = exports.scopeFailureDetail = exports.noTargetsResolved = exports.isTargetCountAbsence = exports.eligibleTargetCount = exports.compareTargets = exports.SUBSCRIPTION_ID_FIELD_RENAMED = void 0;
|
|
1875
|
+
exports.ACCEPTING_A_PROVENANCE_IS_NOT_A_CAPABILITY = exports.RUNNER_PACKAGE_RUNTIME_NOT_PINNED = exports.CONNECTOR_UNAVAILABLE_MESSAGE = exports.ACTION_RUNNABILITY_CAUSE_KINDS = exports.EXECUTION_LOG_ACTIVITY_PHRASE = exports.EXECUTION_LOG_CONNECTION_PHRASE = exports.EXECUTION_LOG_STREAM_PHASES = exports.EXECUTION_LOG_ACTIVITIES = exports.targetsValidationCheck = exports.targetSummarySentence = exports.targetSummaryOf = exports.targetSummaryLabel = exports.targetsUnavailableFrom = exports.targetsUnavailable = exports.targetComparisonSentence = exports.targetComparisonLevel = exports.targetComparisonLabel = exports.TARGETS_NOT_COUNTED = exports.TARGETS_NO_SCOPE = exports.TARGET_COUNT_ABSENCES = exports.TARGET_COMPARISON_KINDS = exports.singleTarget = exports.scopeFailureDetail = exports.noTargetsResolved = exports.isTargetCountAbsence = exports.eligibleTargetCount = exports.compareTargets = exports.REFUSAL_CODES = exports.isRefusalCode = exports.isDecisionCode = exports.isCheckLevel = exports.DECISION_CODES = exports.CHECK_LEVELS = exports.SUBSCRIPTION_ID_FIELD_RENAMED = void 0;
|
|
1486
1876
|
exports.executionLogStreamSentence = executionLogStreamSentence;
|
|
1487
1877
|
exports.actionRunnabilityCopy = actionRunnabilityCopy;
|
|
1488
1878
|
exports.actionRunnabilityHeadline = actionRunnabilityHeadline;
|
|
@@ -1493,6 +1883,42 @@ var require_execution = __commonJS({
|
|
|
1493
1883
|
var brand_1 = require_brand();
|
|
1494
1884
|
exports.SUBSCRIPTION_ID_FIELD_RENAMED = "`subscriptionId` is not accepted on this route. It named an `azure_subscription.id` while this route has always resolved a `connection_scope.id`. The two were the same value while one shim gave a scope the registry row's id; a scope discovered since has an id of its own, and the registry id is either nobody's scope or another connector's. Send `connectionScopeId` \u2014 the value `ExecutionDto.connectionScopeId` reports for a run.";
|
|
1495
1885
|
var validation_1 = require_validation();
|
|
1886
|
+
Object.defineProperty(exports, "CHECK_LEVELS", {
|
|
1887
|
+
enumerable: true,
|
|
1888
|
+
get: /* @__PURE__ */ __name(function() {
|
|
1889
|
+
return validation_1.CHECK_LEVELS;
|
|
1890
|
+
}, "get")
|
|
1891
|
+
});
|
|
1892
|
+
Object.defineProperty(exports, "DECISION_CODES", {
|
|
1893
|
+
enumerable: true,
|
|
1894
|
+
get: /* @__PURE__ */ __name(function() {
|
|
1895
|
+
return validation_1.DECISION_CODES;
|
|
1896
|
+
}, "get")
|
|
1897
|
+
});
|
|
1898
|
+
Object.defineProperty(exports, "isCheckLevel", {
|
|
1899
|
+
enumerable: true,
|
|
1900
|
+
get: /* @__PURE__ */ __name(function() {
|
|
1901
|
+
return validation_1.isCheckLevel;
|
|
1902
|
+
}, "get")
|
|
1903
|
+
});
|
|
1904
|
+
Object.defineProperty(exports, "isDecisionCode", {
|
|
1905
|
+
enumerable: true,
|
|
1906
|
+
get: /* @__PURE__ */ __name(function() {
|
|
1907
|
+
return validation_1.isDecisionCode;
|
|
1908
|
+
}, "get")
|
|
1909
|
+
});
|
|
1910
|
+
Object.defineProperty(exports, "isRefusalCode", {
|
|
1911
|
+
enumerable: true,
|
|
1912
|
+
get: /* @__PURE__ */ __name(function() {
|
|
1913
|
+
return validation_1.isRefusalCode;
|
|
1914
|
+
}, "get")
|
|
1915
|
+
});
|
|
1916
|
+
Object.defineProperty(exports, "REFUSAL_CODES", {
|
|
1917
|
+
enumerable: true,
|
|
1918
|
+
get: /* @__PURE__ */ __name(function() {
|
|
1919
|
+
return validation_1.REFUSAL_CODES;
|
|
1920
|
+
}, "get")
|
|
1921
|
+
});
|
|
1496
1922
|
Object.defineProperty(exports, "compareTargets", {
|
|
1497
1923
|
enumerable: true,
|
|
1498
1924
|
get: /* @__PURE__ */ __name(function() {
|
|
@@ -1634,6 +2060,7 @@ var require_execution = __commonJS({
|
|
|
1634
2060
|
}
|
|
1635
2061
|
__name(executionLogStreamSentence, "executionLogStreamSentence");
|
|
1636
2062
|
var ACTION_RUNNABILITY_CAUSE_KIND_SET = {
|
|
2063
|
+
catalog_blocked: true,
|
|
1637
2064
|
connector_unregistered: true,
|
|
1638
2065
|
package: true,
|
|
1639
2066
|
runner_pool: true,
|
|
@@ -1643,8 +2070,12 @@ var require_execution = __commonJS({
|
|
|
1643
2070
|
};
|
|
1644
2071
|
exports.ACTION_RUNNABILITY_CAUSE_KINDS = Object.keys(ACTION_RUNNABILITY_CAUSE_KIND_SET);
|
|
1645
2072
|
exports.CONNECTOR_UNAVAILABLE_MESSAGE = "This action is not yet available to run.";
|
|
2073
|
+
var CATALOG_BLOCKED_CAUSE = "This workspace does not permit this action.";
|
|
2074
|
+
var CATALOG_BLOCKED_REMEDY = "An administrator of this workspace decides which catalog actions may run here, and can allow it.";
|
|
1646
2075
|
function actionRunnabilityCopy(cause) {
|
|
1647
2076
|
switch (cause.kind) {
|
|
2077
|
+
case "catalog_blocked":
|
|
2078
|
+
return `${CATALOG_BLOCKED_CAUSE} ${CATALOG_BLOCKED_REMEDY}`;
|
|
1648
2079
|
case "package":
|
|
1649
2080
|
return (0, packages_2.actionUnrunnableCopy)(cause.detail);
|
|
1650
2081
|
case "runner_pool": {
|
|
@@ -1676,7 +2107,7 @@ var require_execution = __commonJS({
|
|
|
1676
2107
|
}
|
|
1677
2108
|
__name(describeRoutingPlaces, "describeRoutingPlaces");
|
|
1678
2109
|
function runnerPoolClauses(cause) {
|
|
1679
|
-
const
|
|
2110
|
+
const provenance2 = cause.provenance ? `is ${packages_1.PACKAGE_PROVENANCE_CLAUSES[cause.provenance]}` : (
|
|
1680
2111
|
// every other value this sentence could take is a claim about where bytes came from.
|
|
1681
2112
|
"has no recorded provenance"
|
|
1682
2113
|
);
|
|
@@ -1694,7 +2125,7 @@ var require_execution = __commonJS({
|
|
|
1694
2125
|
* credential it acts with. A refusal that dropped those would be telling an admin the
|
|
1695
2126
|
* decision no longer matters.
|
|
1696
2127
|
*/
|
|
1697
|
-
cause: `${
|
|
2128
|
+
cause: `${provenance2}, and would run on the private runner pool "${cause.poolName}", because that is where runs using this connection execute \u2014 on a machine you own, in a container that shares its host's kernel and acts with this connection's credential.`,
|
|
1698
2129
|
remedy: `${acceptedClause(cause.accepts)} ${POOL_CONSENT_REMEDY}`
|
|
1699
2130
|
};
|
|
1700
2131
|
}
|
|
@@ -1733,6 +2164,8 @@ var require_execution = __commonJS({
|
|
|
1733
2164
|
var POOL_CONSENT_REMEDY = `${brand_1.BRAND_SHORT_NAME} does not vouch for what runs on your machines \u2014 the owner of this pool does. An administrator can accept this provenance under Settings \u2192 Runners, and until they do, nothing of this provenance will be sent there. Built-in actions still run in that pool.`;
|
|
1734
2165
|
function actionRunnabilityHeadline(cause) {
|
|
1735
2166
|
switch (cause.kind) {
|
|
2167
|
+
case "catalog_blocked":
|
|
2168
|
+
return "this workspace does not permit its action \u2014 an administrator of this workspace can allow it";
|
|
1736
2169
|
case "package":
|
|
1737
2170
|
return (0, packages_2.actionUnrunnableHeadline)(cause.detail);
|
|
1738
2171
|
case "runner_pool":
|
|
@@ -1750,6 +2183,8 @@ var require_execution = __commonJS({
|
|
|
1750
2183
|
__name(actionRunnabilityHeadline, "actionRunnabilityHeadline");
|
|
1751
2184
|
function actionRunnabilityRefusal(cause) {
|
|
1752
2185
|
switch (cause.kind) {
|
|
2186
|
+
case "catalog_blocked":
|
|
2187
|
+
return `${CATALOG_BLOCKED_CAUSE} ${CATALOG_BLOCKED_REMEDY} Nothing was started.`;
|
|
1753
2188
|
case "package":
|
|
1754
2189
|
return (0, packages_2.actionUnrunnableRefusal)(cause.detail, cause);
|
|
1755
2190
|
case "runner_pool": {
|
|
@@ -1774,6 +2209,80 @@ var require_execution = __commonJS({
|
|
|
1774
2209
|
}
|
|
1775
2210
|
});
|
|
1776
2211
|
|
|
2212
|
+
// ../contracts/dist/decisions.js
|
|
2213
|
+
var require_decisions = __commonJS({
|
|
2214
|
+
"../contracts/dist/decisions.js"(exports) {
|
|
2215
|
+
"use strict";
|
|
2216
|
+
Object.defineProperty(exports, "__esModule", {
|
|
2217
|
+
value: true
|
|
2218
|
+
});
|
|
2219
|
+
exports.DECISION_ACKNOWLEDGEMENT = void 0;
|
|
2220
|
+
exports.recordedDecisionsOf = recordedDecisionsOf;
|
|
2221
|
+
exports.raisedDecisionCodes = raisedDecisionCodes;
|
|
2222
|
+
exports.decisionMismatch = decisionMismatch;
|
|
2223
|
+
exports.decisionMismatchSentence = decisionMismatchSentence;
|
|
2224
|
+
var validation_1 = require_validation();
|
|
2225
|
+
function recordedDecisionsOf(stored) {
|
|
2226
|
+
if (!Array.isArray(stored)) return [];
|
|
2227
|
+
const read = [];
|
|
2228
|
+
for (const entry of stored) {
|
|
2229
|
+
if (typeof entry !== "object" || entry === null) continue;
|
|
2230
|
+
const { code, acknowledgedBy, acknowledgedAt } = entry;
|
|
2231
|
+
if (!(0, validation_1.isDecisionCode)(code)) continue;
|
|
2232
|
+
if (typeof acknowledgedBy !== "string" || acknowledgedBy.length === 0) continue;
|
|
2233
|
+
if (typeof acknowledgedAt !== "string" || Number.isNaN(Date.parse(acknowledgedAt))) continue;
|
|
2234
|
+
if (read.some((decision) => decision.code === code)) continue;
|
|
2235
|
+
read.push({
|
|
2236
|
+
code,
|
|
2237
|
+
acknowledgedBy,
|
|
2238
|
+
acknowledgedAt
|
|
2239
|
+
});
|
|
2240
|
+
}
|
|
2241
|
+
return read;
|
|
2242
|
+
}
|
|
2243
|
+
__name(recordedDecisionsOf, "recordedDecisionsOf");
|
|
2244
|
+
function raisedDecisionCodes(checks) {
|
|
2245
|
+
const raised = [];
|
|
2246
|
+
for (const check of checks) {
|
|
2247
|
+
if (check.decision && !raised.includes(check.decision)) raised.push(check.decision);
|
|
2248
|
+
}
|
|
2249
|
+
return raised;
|
|
2250
|
+
}
|
|
2251
|
+
__name(raisedDecisionCodes, "raisedDecisionCodes");
|
|
2252
|
+
function decisionMismatch(raised, acknowledged) {
|
|
2253
|
+
const unacknowledged = raised.filter((code) => !acknowledged.includes(code));
|
|
2254
|
+
const notRaised = acknowledged.filter((code) => !raised.includes(code));
|
|
2255
|
+
return unacknowledged.length === 0 && notRaised.length === 0 ? null : {
|
|
2256
|
+
unacknowledged,
|
|
2257
|
+
notRaised
|
|
2258
|
+
};
|
|
2259
|
+
}
|
|
2260
|
+
__name(decisionMismatch, "decisionMismatch");
|
|
2261
|
+
function decisionMismatchSentence(mismatch) {
|
|
2262
|
+
const parts = [];
|
|
2263
|
+
if (mismatch.unacknowledged.length > 0) {
|
|
2264
|
+
parts.push(`the plan raised ${quoteCodes(mismatch.unacknowledged)}, which ${mismatch.unacknowledged.length === 1 ? "was" : "were"} not acknowledged`);
|
|
2265
|
+
}
|
|
2266
|
+
if (mismatch.notRaised.length > 0) {
|
|
2267
|
+
parts.push(`${quoteCodes(mismatch.notRaised)} ${mismatch.notRaised.length === 1 ? "was" : "were"} acknowledged but the plan does not raise ${mismatch.notRaised.length === 1 ? "it" : "them"}`);
|
|
2268
|
+
}
|
|
2269
|
+
return `This run was not submitted: ${parts.join(", and ")}. The checks were run again at submit and decide what needs acknowledging \u2014 review the plan and submit again.`;
|
|
2270
|
+
}
|
|
2271
|
+
__name(decisionMismatchSentence, "decisionMismatchSentence");
|
|
2272
|
+
function quoteCodes(codes) {
|
|
2273
|
+
return codes.map((code) => `"${code}"`).join(", ");
|
|
2274
|
+
}
|
|
2275
|
+
__name(quoteCodes, "quoteCodes");
|
|
2276
|
+
exports.DECISION_ACKNOWLEDGEMENT = {
|
|
2277
|
+
"disk.recentlyDetached": "Delete it even though it was detached recently",
|
|
2278
|
+
"disk.customerKey": "Delete it \u2014 restoring later depends on this key staying enabled",
|
|
2279
|
+
"disk.customerKeyUnverified": "Delete it without confirmation that the key is enabled",
|
|
2280
|
+
"disk.guestEncrypted": "Delete it \u2014 restoring later depends on the guest's encryption secrets",
|
|
2281
|
+
"disk.noSnapshot": "Delete it with no snapshot \u2014 this cannot be undone"
|
|
2282
|
+
};
|
|
2283
|
+
}
|
|
2284
|
+
});
|
|
2285
|
+
|
|
1777
2286
|
// ../contracts/dist/execution-site.js
|
|
1778
2287
|
var require_execution_site = __commonJS({
|
|
1779
2288
|
"../contracts/dist/execution-site.js"(exports) {
|
|
@@ -1858,7 +2367,13 @@ var require_resources = __commonJS({
|
|
|
1858
2367
|
Object.defineProperty(exports, "__esModule", {
|
|
1859
2368
|
value: true
|
|
1860
2369
|
});
|
|
1861
|
-
exports.DISCOVERY_TYPE_PATTERN = exports.
|
|
2370
|
+
exports.DISCOVERY_TYPE_PATTERN = exports.LEGACY_DISCOVERY_PROVIDER = exports.DISCOVERY_VOCABULARY = void 0;
|
|
2371
|
+
exports.discoveryTypesOf = discoveryTypesOf;
|
|
2372
|
+
exports.declaredDiscoveryTypes = declaredDiscoveryTypes;
|
|
2373
|
+
exports.liveDiscoveryTypes = liveDiscoveryTypes;
|
|
2374
|
+
exports.canonicalDiscoveryId = canonicalDiscoveryId;
|
|
2375
|
+
exports.resolveDiscoveryType = resolveDiscoveryType;
|
|
2376
|
+
exports.isSecretReference = isSecretReference;
|
|
1862
2377
|
exports.parseDiscoveryType = parseDiscoveryType;
|
|
1863
2378
|
exports.formatDiscoveryType = formatDiscoveryType;
|
|
1864
2379
|
exports.discoveryTypeSpec = discoveryTypeSpec;
|
|
@@ -1874,16 +2389,20 @@ var require_resources = __commonJS({
|
|
|
1874
2389
|
resourceGroup: {
|
|
1875
2390
|
requires: [],
|
|
1876
2391
|
routable: false,
|
|
1877
|
-
identity: null
|
|
2392
|
+
identity: null,
|
|
2393
|
+
secretRef: false
|
|
1878
2394
|
},
|
|
1879
2395
|
// ROUTABLE BUT NOT NAMABLE, and the two are different questions. A rule matches a vault by
|
|
1880
2396
|
// its NAME and its tags, which discovery supplies; an ARM vault id needs the resource group
|
|
1881
2397
|
// this vocabulary never asks for (`requires` is empty so vaults list subscription-wide). See
|
|
1882
2398
|
// `identity` on the spec above — null is the honest answer, not an omission.
|
|
2399
|
+
// NOT a secret reference: a vault CONTAINS secrets, and naming one reveals nothing a run
|
|
2400
|
+
// could read. The secret inside it is the reference (`keyVaultSecret` below).
|
|
1883
2401
|
keyVault: {
|
|
1884
2402
|
requires: [],
|
|
1885
2403
|
routable: true,
|
|
1886
|
-
identity: null
|
|
2404
|
+
identity: null,
|
|
2405
|
+
secretRef: false
|
|
1887
2406
|
},
|
|
1888
2407
|
// ★ A DATA-PLANE URI, NOT AN ARM PATH, AND IT IS WHAT DISCOVERY ALREADY RETURNS. The Key
|
|
1889
2408
|
// Vault SDK reports `SecretProperties.id` as `https://<vault>.vault.azure.net/secrets/<name>`
|
|
@@ -1895,27 +2414,33 @@ var require_resources = __commonJS({
|
|
|
1895
2414
|
"vault"
|
|
1896
2415
|
],
|
|
1897
2416
|
routable: true,
|
|
1898
|
-
identity: "https://{vault}.vault.azure.net/secrets/{name}"
|
|
2417
|
+
identity: "https://{vault}.vault.azure.net/secrets/{name}",
|
|
2418
|
+
// ★ THE ONE TYPE TODAY WHOSE VALUE POINTS AT A SECRET (docs/122 §3.5). The parameter holds
|
|
2419
|
+
// the secret's NAME within its vault; nothing in the platform ever reads the value behind it.
|
|
2420
|
+
secretRef: true
|
|
1899
2421
|
},
|
|
1900
2422
|
// A catalogue value. Nothing is reached by naming a region.
|
|
1901
2423
|
location: {
|
|
1902
2424
|
requires: [],
|
|
1903
2425
|
routable: false,
|
|
1904
|
-
identity: null
|
|
2426
|
+
identity: null,
|
|
2427
|
+
secretRef: false
|
|
1905
2428
|
},
|
|
1906
2429
|
managedDisk: {
|
|
1907
2430
|
requires: [
|
|
1908
2431
|
"resourceGroup"
|
|
1909
2432
|
],
|
|
1910
2433
|
routable: true,
|
|
1911
|
-
identity: "/subscriptions/{subscription}/resourceGroups/{resourceGroup}/providers/Microsoft.Compute/disks/{name}"
|
|
2434
|
+
identity: "/subscriptions/{subscription}/resourceGroups/{resourceGroup}/providers/Microsoft.Compute/disks/{name}",
|
|
2435
|
+
secretRef: false
|
|
1912
2436
|
},
|
|
1913
2437
|
sqlServer: {
|
|
1914
2438
|
requires: [
|
|
1915
2439
|
"resourceGroup"
|
|
1916
2440
|
],
|
|
1917
2441
|
routable: true,
|
|
1918
|
-
identity: "/subscriptions/{subscription}/resourceGroups/{resourceGroup}/providers/Microsoft.Sql/servers/{name}"
|
|
2442
|
+
identity: "/subscriptions/{subscription}/resourceGroups/{resourceGroup}/providers/Microsoft.Sql/servers/{name}",
|
|
2443
|
+
secretRef: false
|
|
1919
2444
|
},
|
|
1920
2445
|
sqlDatabase: {
|
|
1921
2446
|
requires: [
|
|
@@ -1923,7 +2448,8 @@ var require_resources = __commonJS({
|
|
|
1923
2448
|
"server"
|
|
1924
2449
|
],
|
|
1925
2450
|
routable: true,
|
|
1926
|
-
identity: "/subscriptions/{subscription}/resourceGroups/{resourceGroup}/providers/Microsoft.Sql/servers/{server}/databases/{name}"
|
|
2451
|
+
identity: "/subscriptions/{subscription}/resourceGroups/{resourceGroup}/providers/Microsoft.Sql/servers/{server}/databases/{name}",
|
|
2452
|
+
secretRef: false
|
|
1927
2453
|
},
|
|
1928
2454
|
// The one type where LISTING and IDENTIFYING are different questions. It lists
|
|
1929
2455
|
// SUBSCRIPTION-WIDE when no resource group is given (`virtualMachines.listAll()`,
|
|
@@ -1943,7 +2469,8 @@ var require_resources = __commonJS({
|
|
|
1943
2469
|
"resourceGroup"
|
|
1944
2470
|
],
|
|
1945
2471
|
routable: true,
|
|
1946
|
-
identity: "/subscriptions/{subscription}/resourceGroups/{resourceGroup}/providers/Microsoft.Compute/virtualMachines/{name}"
|
|
2472
|
+
identity: "/subscriptions/{subscription}/resourceGroups/{resourceGroup}/providers/Microsoft.Compute/virtualMachines/{name}",
|
|
2473
|
+
secretRef: false
|
|
1947
2474
|
},
|
|
1948
2475
|
// The sizes ONE machine can actually be resized to right now — not the region's SKU
|
|
1949
2476
|
// catalogue. `requires` is genuinely both fields' answer here: the safe set cannot be
|
|
@@ -1957,16 +2484,53 @@ var require_resources = __commonJS({
|
|
|
1957
2484
|
"vm"
|
|
1958
2485
|
],
|
|
1959
2486
|
routable: false,
|
|
1960
|
-
identity: null
|
|
2487
|
+
identity: null,
|
|
2488
|
+
secretRef: false
|
|
1961
2489
|
}
|
|
1962
2490
|
};
|
|
1963
|
-
|
|
2491
|
+
var DECLARED_DISCOVERY = {
|
|
1964
2492
|
azure: AZURE_DISCOVERY_TYPES,
|
|
1965
2493
|
aws: {},
|
|
1966
2494
|
gcp: {},
|
|
1967
2495
|
terraform: {}
|
|
1968
2496
|
};
|
|
1969
|
-
exports.
|
|
2497
|
+
exports.DISCOVERY_VOCABULARY = DECLARED_DISCOVERY;
|
|
2498
|
+
exports.LEGACY_DISCOVERY_PROVIDER = "azure";
|
|
2499
|
+
function discoveryTypesOf(provider) {
|
|
2500
|
+
return Object.keys(exports.DISCOVERY_VOCABULARY[provider]).map((type) => formatDiscoveryType(provider, type));
|
|
2501
|
+
}
|
|
2502
|
+
__name(discoveryTypesOf, "discoveryTypesOf");
|
|
2503
|
+
function declaredDiscoveryTypes() {
|
|
2504
|
+
return enums_1.PROVIDERS.flatMap(discoveryTypesOf);
|
|
2505
|
+
}
|
|
2506
|
+
__name(declaredDiscoveryTypes, "declaredDiscoveryTypes");
|
|
2507
|
+
function liveDiscoveryTypes(registered) {
|
|
2508
|
+
const providers = new Set(registered);
|
|
2509
|
+
return enums_1.PROVIDERS.filter((provider) => providers.has(provider)).flatMap(discoveryTypesOf);
|
|
2510
|
+
}
|
|
2511
|
+
__name(liveDiscoveryTypes, "liveDiscoveryTypes");
|
|
2512
|
+
function canonicalDiscoveryId(value) {
|
|
2513
|
+
const parsed = parseDiscoveryType(value.trim(), exports.LEGACY_DISCOVERY_PROVIDER);
|
|
2514
|
+
return parsed ? formatDiscoveryType(parsed.provider, parsed.type) : null;
|
|
2515
|
+
}
|
|
2516
|
+
__name(canonicalDiscoveryId, "canonicalDiscoveryId");
|
|
2517
|
+
function resolveDiscoveryType(value) {
|
|
2518
|
+
const parsed = parseDiscoveryType(value.trim(), exports.LEGACY_DISCOVERY_PROVIDER);
|
|
2519
|
+
if (!parsed) return null;
|
|
2520
|
+
const spec = discoveryTypeSpec(parsed.provider, parsed.type);
|
|
2521
|
+
if (!spec) return null;
|
|
2522
|
+
return {
|
|
2523
|
+
id: formatDiscoveryType(parsed.provider, parsed.type),
|
|
2524
|
+
provider: parsed.provider,
|
|
2525
|
+
type: parsed.type,
|
|
2526
|
+
spec
|
|
2527
|
+
};
|
|
2528
|
+
}
|
|
2529
|
+
__name(resolveDiscoveryType, "resolveDiscoveryType");
|
|
2530
|
+
function isSecretReference(discover) {
|
|
2531
|
+
return discover ? resolveDiscoveryType(discover)?.spec.secretRef === true : false;
|
|
2532
|
+
}
|
|
2533
|
+
__name(isSecretReference, "isSecretReference");
|
|
1970
2534
|
exports.DISCOVERY_TYPE_PATTERN = /^(?:([a-z][a-z0-9]*)\/)?([a-z][a-zA-Z0-9]{0,63})$/;
|
|
1971
2535
|
function parseDiscoveryType(value, fallbackProvider) {
|
|
1972
2536
|
const match = exports.DISCOVERY_TYPE_PATTERN.exec(value);
|
|
@@ -1990,7 +2554,9 @@ var require_resources = __commonJS({
|
|
|
1990
2554
|
}
|
|
1991
2555
|
__name(formatDiscoveryType, "formatDiscoveryType");
|
|
1992
2556
|
function discoveryTypeSpec(provider, type) {
|
|
1993
|
-
|
|
2557
|
+
if (!Object.prototype.hasOwnProperty.call(exports.DISCOVERY_VOCABULARY, provider)) return void 0;
|
|
2558
|
+
const vocabulary = exports.DISCOVERY_VOCABULARY[provider];
|
|
2559
|
+
return Object.prototype.hasOwnProperty.call(vocabulary, type) ? vocabulary[type] : void 0;
|
|
1994
2560
|
}
|
|
1995
2561
|
__name(discoveryTypeSpec, "discoveryTypeSpec");
|
|
1996
2562
|
function dependsOnLookup(keys, dependsOn) {
|
|
@@ -2291,6 +2857,28 @@ var require_runs = __commonJS({
|
|
|
2291
2857
|
}
|
|
2292
2858
|
});
|
|
2293
2859
|
|
|
2860
|
+
// ../contracts/dist/evidence-pack.js
|
|
2861
|
+
var require_evidence_pack = __commonJS({
|
|
2862
|
+
"../contracts/dist/evidence-pack.js"(exports) {
|
|
2863
|
+
"use strict";
|
|
2864
|
+
Object.defineProperty(exports, "__esModule", {
|
|
2865
|
+
value: true
|
|
2866
|
+
});
|
|
2867
|
+
exports.EVIDENCE_EXPORTED_AUDIT_ACTION = exports.EVIDENCE_DIGEST_HEADER = void 0;
|
|
2868
|
+
exports.evidencePackFilename = evidencePackFilename;
|
|
2869
|
+
exports.EVIDENCE_DIGEST_HEADER = "X-Evidence-Digest";
|
|
2870
|
+
exports.EVIDENCE_EXPORTED_AUDIT_ACTION = "operation.evidence_exported";
|
|
2871
|
+
function evidencePackFilename(operationKey, from, to) {
|
|
2872
|
+
return `${operationKey}-evidence-${compactInstant(from)}-${compactInstant(to)}.json`;
|
|
2873
|
+
}
|
|
2874
|
+
__name(evidencePackFilename, "evidencePackFilename");
|
|
2875
|
+
function compactInstant(iso) {
|
|
2876
|
+
return iso.replace(/\.\d+(?=Z|[+-]\d{2}:?\d{2}$)/, "").replace(/[-:]/g, "");
|
|
2877
|
+
}
|
|
2878
|
+
__name(compactInstant, "compactInstant");
|
|
2879
|
+
}
|
|
2880
|
+
});
|
|
2881
|
+
|
|
2294
2882
|
// ../contracts/dist/package-egress.js
|
|
2295
2883
|
var require_package_egress = __commonJS({
|
|
2296
2884
|
"../contracts/dist/package-egress.js"(exports) {
|
|
@@ -2555,9 +3143,9 @@ var require_runners = __commonJS({
|
|
|
2555
3143
|
authored: false
|
|
2556
3144
|
};
|
|
2557
3145
|
exports.RUNNER_POOL_DEFAULT_ACCEPTS_PROVENANCE = package_provenance_1.PACKAGE_PROVENANCE_KINDS.filter((kind) => exports.RUNNER_POOL_ACCEPTS_PROVENANCE_BY_DEFAULT[kind]);
|
|
2558
|
-
function poolAcceptsProvenance(accepts,
|
|
2559
|
-
if (
|
|
2560
|
-
return accepts.includes(
|
|
3146
|
+
function poolAcceptsProvenance(accepts, provenance2) {
|
|
3147
|
+
if (provenance2 === null) return false;
|
|
3148
|
+
return accepts.includes(provenance2);
|
|
2561
3149
|
}
|
|
2562
3150
|
__name(poolAcceptsProvenance, "poolAcceptsProvenance");
|
|
2563
3151
|
function containerNameFor(runnerName) {
|
|
@@ -3385,11 +3973,11 @@ var require_workspace_domain = __commonJS({
|
|
|
3385
3973
|
"held_elsewhere"
|
|
3386
3974
|
];
|
|
3387
3975
|
exports.DOMAIN_VERIFICATION_RECORD_PREFIX = "runveric-domain-verification=";
|
|
3388
|
-
function domainVerificationRecord(domain,
|
|
3976
|
+
function domainVerificationRecord(domain, token2) {
|
|
3389
3977
|
return {
|
|
3390
3978
|
name: domain,
|
|
3391
3979
|
type: "TXT",
|
|
3392
|
-
value: `${exports.DOMAIN_VERIFICATION_RECORD_PREFIX}${
|
|
3980
|
+
value: `${exports.DOMAIN_VERIFICATION_RECORD_PREFIX}${token2}`
|
|
3393
3981
|
};
|
|
3394
3982
|
}
|
|
3395
3983
|
__name(domainVerificationRecord, "domainVerificationRecord");
|
|
@@ -3572,9 +4160,16 @@ var require_dist = __commonJS({
|
|
|
3572
4160
|
__exportStar(require_tenant_users(), exports);
|
|
3573
4161
|
__exportStar(require_invitations(), exports);
|
|
3574
4162
|
__exportStar(require_groups(), exports);
|
|
4163
|
+
__exportStar(require_catalog_policy(), exports);
|
|
3575
4164
|
__exportStar(require_catalog(), exports);
|
|
4165
|
+
__exportStar(require_catalog_release(), exports);
|
|
4166
|
+
__exportStar(require_action_repository(), exports);
|
|
4167
|
+
__exportStar(require_catalog_release_spec(), exports);
|
|
4168
|
+
__exportStar(require_catalog_lock(), exports);
|
|
4169
|
+
__exportStar(require_catalog_manifest_placeholders(), exports);
|
|
3576
4170
|
__exportStar(require_change_control(), exports);
|
|
3577
4171
|
__exportStar(require_execution(), exports);
|
|
4172
|
+
__exportStar(require_decisions(), exports);
|
|
3578
4173
|
__exportStar(require_execution_site(), exports);
|
|
3579
4174
|
__exportStar(require_run_placement(), exports);
|
|
3580
4175
|
__exportStar(require_connections(), exports);
|
|
@@ -3585,6 +4180,7 @@ var require_dist = __commonJS({
|
|
|
3585
4180
|
__exportStar(require_scheduling(), exports);
|
|
3586
4181
|
__exportStar(require_operations(), exports);
|
|
3587
4182
|
__exportStar(require_runs(), exports);
|
|
4183
|
+
__exportStar(require_evidence_pack(), exports);
|
|
3588
4184
|
__exportStar(require_package_tier(), exports);
|
|
3589
4185
|
__exportStar(require_package_provenance(), exports);
|
|
3590
4186
|
__exportStar(require_packages(), exports);
|
|
@@ -5095,7 +5691,7 @@ var require_authoring_lint = __commonJS({
|
|
|
5095
5691
|
if (!isRecord(permission) || !Array.isArray(permission.actions)) return;
|
|
5096
5692
|
permission.actions.forEach((action, actionIndex) => {
|
|
5097
5693
|
if (typeof action !== "string" || action.includes("*")) return;
|
|
5098
|
-
if (permissionTokens(action).some((
|
|
5694
|
+
if (permissionTokens(action).some((token2) => haystack.includes(token2))) return;
|
|
5099
5695
|
findings.push({
|
|
5100
5696
|
severity: "warning",
|
|
5101
5697
|
rule: "package/permission-possibly-unused",
|
|
@@ -6941,67 +7537,7 @@ var require_dist2 = __commonJS({
|
|
|
6941
7537
|
});
|
|
6942
7538
|
|
|
6943
7539
|
// package.json
|
|
6944
|
-
var version = "0.
|
|
6945
|
-
|
|
6946
|
-
// src/check.ts
|
|
6947
|
-
var import_action_manifest = __toESM(require_dist2());
|
|
6948
|
-
import { resolve } from "path";
|
|
6949
|
-
|
|
6950
|
-
// src/package-dir.ts
|
|
6951
|
-
import { readdir, readFile, stat } from "fs/promises";
|
|
6952
|
-
import { join, relative, sep } from "path";
|
|
6953
|
-
var IGNORED_DIRECTORIES = /* @__PURE__ */ new Set([
|
|
6954
|
-
".git",
|
|
6955
|
-
".runveric",
|
|
6956
|
-
"node_modules",
|
|
6957
|
-
".venv",
|
|
6958
|
-
"__pycache__",
|
|
6959
|
-
".DS_Store"
|
|
6960
|
-
]);
|
|
6961
|
-
var MAX_FILES = 2e3;
|
|
6962
|
-
var MAX_TOTAL_BYTES = 16 * 1024 * 1024;
|
|
6963
|
-
var PackageDirectoryError = class extends Error {
|
|
6964
|
-
static {
|
|
6965
|
-
__name(this, "PackageDirectoryError");
|
|
6966
|
-
}
|
|
6967
|
-
};
|
|
6968
|
-
async function readPackageDirectory(root) {
|
|
6969
|
-
const properties = await stat(root).catch(() => null);
|
|
6970
|
-
if (!properties?.isDirectory()) {
|
|
6971
|
-
throw new PackageDirectoryError(`${root} is not a directory.`);
|
|
6972
|
-
}
|
|
6973
|
-
const files = /* @__PURE__ */ new Map();
|
|
6974
|
-
let totalBytes = 0;
|
|
6975
|
-
const walk = /* @__PURE__ */ __name(async (directory) => {
|
|
6976
|
-
for (const entry of await readdir(directory, {
|
|
6977
|
-
withFileTypes: true
|
|
6978
|
-
})) {
|
|
6979
|
-
if (IGNORED_DIRECTORIES.has(entry.name)) continue;
|
|
6980
|
-
const full = join(directory, entry.name);
|
|
6981
|
-
if (entry.isDirectory()) {
|
|
6982
|
-
await walk(full);
|
|
6983
|
-
continue;
|
|
6984
|
-
}
|
|
6985
|
-
if (!entry.isFile()) continue;
|
|
6986
|
-
if (files.size >= MAX_FILES) {
|
|
6987
|
-
throw new PackageDirectoryError(`This directory holds more than ${MAX_FILES} files. That is almost certainly not a single action package \u2014 run this from the package directory itself.`);
|
|
6988
|
-
}
|
|
6989
|
-
const contents = await readFile(full);
|
|
6990
|
-
totalBytes += contents.byteLength;
|
|
6991
|
-
if (totalBytes > MAX_TOTAL_BYTES) {
|
|
6992
|
-
throw new PackageDirectoryError(`This directory holds more than ${MAX_TOTAL_BYTES / (1024 * 1024)}MB. An action package is source, not artifacts \u2014 add build output to .gitignore.`);
|
|
6993
|
-
}
|
|
6994
|
-
files.set(toPackagePath(root, full), contents);
|
|
6995
|
-
}
|
|
6996
|
-
}, "walk");
|
|
6997
|
-
await walk(root);
|
|
6998
|
-
return files;
|
|
6999
|
-
}
|
|
7000
|
-
__name(readPackageDirectory, "readPackageDirectory");
|
|
7001
|
-
function toPackagePath(root, full) {
|
|
7002
|
-
return relative(root, full).split(sep).join("/");
|
|
7003
|
-
}
|
|
7004
|
-
__name(toPackagePath, "toPackagePath");
|
|
7540
|
+
var version = "0.2.0";
|
|
7005
7541
|
|
|
7006
7542
|
// src/report.ts
|
|
7007
7543
|
var useColour = process.stdout.isTTY === true && !process.env.NO_COLOR;
|
|
@@ -7110,10 +7646,515 @@ function printResult(result) {
|
|
|
7110
7646
|
}
|
|
7111
7647
|
__name(printResult, "printResult");
|
|
7112
7648
|
|
|
7113
|
-
// src/
|
|
7649
|
+
// src/catalog/publish-action.ts
|
|
7650
|
+
var import_contracts2 = __toESM(require_dist());
|
|
7651
|
+
import { readFileSync } from "fs";
|
|
7652
|
+
import { dirname, resolve } from "path";
|
|
7653
|
+
import { parse as parseYaml } from "yaml";
|
|
7654
|
+
|
|
7655
|
+
// src/catalog/artifact.ts
|
|
7114
7656
|
var import_contracts = __toESM(require_dist());
|
|
7657
|
+
import { execFileSync } from "child_process";
|
|
7658
|
+
import { createHash } from "crypto";
|
|
7659
|
+
function parseRepository(ref, flag) {
|
|
7660
|
+
if (!import_contracts.ARTIFACT_REPOSITORY_PATTERN.test(ref)) {
|
|
7661
|
+
throw new Error(`${flag} "${ref}" is not a bare registry repository (host[:port]/path, lowercase, no scheme, no tag, no digest). A catalog artifact is addressed by digest; tags are for humans.`);
|
|
7662
|
+
}
|
|
7663
|
+
const cut = ref.indexOf("/");
|
|
7664
|
+
return {
|
|
7665
|
+
ref,
|
|
7666
|
+
host: ref.slice(0, cut),
|
|
7667
|
+
path: ref.slice(cut + 1),
|
|
7668
|
+
namespace: ref.slice(0, ref.lastIndexOf("/"))
|
|
7669
|
+
};
|
|
7670
|
+
}
|
|
7671
|
+
__name(parseRepository, "parseRepository");
|
|
7672
|
+
var isDigest = /* @__PURE__ */ __name((value) => import_contracts.ARTIFACT_DIGEST_PATTERN.test(value), "isDigest");
|
|
7673
|
+
var TAG_PATTERN = /^[A-Za-z0-9_][A-Za-z0-9._-]{0,127}$/;
|
|
7674
|
+
function requireTag(tag, origin2) {
|
|
7675
|
+
if (!TAG_PATTERN.test(tag)) {
|
|
7676
|
+
throw new Error(`${origin2} gives the tag "${tag}", which a registry cannot hold: letters, digits, "_", "." and "-", starting with a letter, digit or "_", at most 128 characters. Pass --tag.`);
|
|
7677
|
+
}
|
|
7678
|
+
}
|
|
7679
|
+
__name(requireTag, "requireTag");
|
|
7680
|
+
var LOOPBACK = /^(localhost|127\.0\.0\.1|\[::1\])(:[0-9]+)?$/;
|
|
7681
|
+
var origin = /* @__PURE__ */ __name((host) => `${LOOPBACK.test(host) ? "http" : "https"}://${host}`, "origin");
|
|
7682
|
+
var sha256 = /* @__PURE__ */ __name((bytes) => `sha256:${createHash("sha256").update(bytes).digest("hex")}`, "sha256");
|
|
7683
|
+
var EMPTY_CONFIG = Buffer.from("{}");
|
|
7684
|
+
var EMPTY_CONFIG_DESCRIPTOR = {
|
|
7685
|
+
mediaType: "application/vnd.oci.empty.v1+json",
|
|
7686
|
+
digest: sha256(EMPTY_CONFIG),
|
|
7687
|
+
size: EMPTY_CONFIG.length
|
|
7688
|
+
};
|
|
7689
|
+
var OCI_MANIFEST = "application/vnd.oci.image.manifest.v1+json";
|
|
7690
|
+
function provenance(flags, dir) {
|
|
7691
|
+
const git = /* @__PURE__ */ __name((...args) => {
|
|
7692
|
+
try {
|
|
7693
|
+
return execFileSync("git", [
|
|
7694
|
+
"-C",
|
|
7695
|
+
dir,
|
|
7696
|
+
...args
|
|
7697
|
+
], {
|
|
7698
|
+
encoding: "utf8",
|
|
7699
|
+
stdio: [
|
|
7700
|
+
"ignore",
|
|
7701
|
+
"pipe",
|
|
7702
|
+
"ignore"
|
|
7703
|
+
]
|
|
7704
|
+
}).trim();
|
|
7705
|
+
} catch {
|
|
7706
|
+
return "";
|
|
7707
|
+
}
|
|
7708
|
+
}, "git");
|
|
7709
|
+
const actions = process.env.GITHUB_SERVER_URL && process.env.GITHUB_REPOSITORY ? `${process.env.GITHUB_SERVER_URL}/${process.env.GITHUB_REPOSITORY}` : "";
|
|
7710
|
+
const repository = flags.repository ?? (actions || git("remote", "get-url", "origin"));
|
|
7711
|
+
const commit = flags.commit ?? (process.env.GITHUB_SHA || git("rev-parse", "HEAD"));
|
|
7712
|
+
if (!repository || !commit) {
|
|
7713
|
+
throw new Error("Provenance is required and could not be determined. Pass --repository <url> and --commit <sha> (in GitHub Actions, GITHUB_REPOSITORY and GITHUB_SHA supply them).");
|
|
7714
|
+
}
|
|
7715
|
+
return {
|
|
7716
|
+
repository,
|
|
7717
|
+
commit,
|
|
7718
|
+
publishedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
7719
|
+
};
|
|
7720
|
+
}
|
|
7721
|
+
__name(provenance, "provenance");
|
|
7722
|
+
function buildArtifact(document) {
|
|
7723
|
+
const documentBytes = Buffer.from(`${JSON.stringify(document, null, 2)}
|
|
7724
|
+
`);
|
|
7725
|
+
const manifest = {
|
|
7726
|
+
schemaVersion: 2,
|
|
7727
|
+
mediaType: OCI_MANIFEST,
|
|
7728
|
+
artifactType: import_contracts.CATALOG_ARTIFACT_MEDIA_TYPE,
|
|
7729
|
+
config: EMPTY_CONFIG_DESCRIPTOR,
|
|
7730
|
+
layers: [
|
|
7731
|
+
{
|
|
7732
|
+
mediaType: import_contracts.CATALOG_ARTIFACT_MEDIA_TYPE,
|
|
7733
|
+
digest: sha256(documentBytes),
|
|
7734
|
+
size: documentBytes.length
|
|
7735
|
+
}
|
|
7736
|
+
],
|
|
7737
|
+
/*
|
|
7738
|
+
* ★ SOURCE AND REVISION ARE FOR THE REGISTRY, NOT THE RESOLVER (docs/127 A.1). GHCR connects
|
|
7739
|
+
* a package to its repository through `org.opencontainers.image.source`, and that link is what
|
|
7740
|
+
* lets the repository's workflow token keep publishing to the package its first run created.
|
|
7741
|
+
* The resolver reads none of these — the document's own provenance is the record — so an
|
|
7742
|
+
* artifact published without them still resolves.
|
|
7743
|
+
*/
|
|
7744
|
+
annotations: {
|
|
7745
|
+
"org.opencontainers.image.created": document.provenance.publishedAt,
|
|
7746
|
+
"org.opencontainers.image.source": document.provenance.repository,
|
|
7747
|
+
"org.opencontainers.image.revision": document.provenance.commit
|
|
7748
|
+
}
|
|
7749
|
+
};
|
|
7750
|
+
const manifestBytes = Buffer.from(JSON.stringify(manifest));
|
|
7751
|
+
return {
|
|
7752
|
+
documentBytes,
|
|
7753
|
+
manifestBytes,
|
|
7754
|
+
manifestDigest: sha256(manifestBytes)
|
|
7755
|
+
};
|
|
7756
|
+
}
|
|
7757
|
+
__name(buildArtifact, "buildArtifact");
|
|
7758
|
+
function basicCredential() {
|
|
7759
|
+
const pat = process.env.GHCR_TOKEN;
|
|
7760
|
+
if (pat) return Buffer.from(`x:${pat}`).toString("base64");
|
|
7761
|
+
const workflow = process.env.GITHUB_TOKEN;
|
|
7762
|
+
if (workflow) return Buffer.from(`${process.env.GITHUB_ACTOR || "x"}:${workflow}`).toString("base64");
|
|
7763
|
+
return void 0;
|
|
7764
|
+
}
|
|
7765
|
+
__name(basicCredential, "basicCredential");
|
|
7766
|
+
var tokens = /* @__PURE__ */ new Map();
|
|
7767
|
+
async function token(repository, challenge) {
|
|
7768
|
+
const field = /* @__PURE__ */ __name((name) => new RegExp(`${name}="([^"]*)"`).exec(challenge ?? "")?.[1], "field");
|
|
7769
|
+
const realm = field("realm");
|
|
7770
|
+
if (!realm) throw new Error(`${repository.host} asked for credentials without a Bearer challenge.`);
|
|
7771
|
+
const url = new URL(realm);
|
|
7772
|
+
const service = field("service");
|
|
7773
|
+
if (service) url.searchParams.set("service", service);
|
|
7774
|
+
url.searchParams.set("scope", `repository:${repository.path}:pull,push`);
|
|
7775
|
+
const credential = basicCredential();
|
|
7776
|
+
const answer = await fetch(url, {
|
|
7777
|
+
headers: credential ? {
|
|
7778
|
+
Authorization: `Basic ${credential}`
|
|
7779
|
+
} : {}
|
|
7780
|
+
});
|
|
7781
|
+
if (!answer.ok) {
|
|
7782
|
+
throw new Error(`${repository.host} refused a push token for ${repository.path}: HTTP ${answer.status}` + (credential ? "." : " \u2014 set GHCR_TOKEN to a token with write:packages, or in a workflow GITHUB_TOKEN with packages: write."));
|
|
7783
|
+
}
|
|
7784
|
+
const body = await answer.json();
|
|
7785
|
+
const value = body.token ?? body.access_token ?? "";
|
|
7786
|
+
tokens.set(repository.path, value);
|
|
7787
|
+
return value;
|
|
7788
|
+
}
|
|
7789
|
+
__name(token, "token");
|
|
7790
|
+
async function call(repository, method, path, { headers = {}, body } = {}) {
|
|
7791
|
+
const url = path.startsWith("http") ? path : `${origin(repository.host)}/v2/${repository.path}/${path}`;
|
|
7792
|
+
const send = /* @__PURE__ */ __name((bearer) => fetch(url, {
|
|
7793
|
+
method,
|
|
7794
|
+
body,
|
|
7795
|
+
redirect: "follow",
|
|
7796
|
+
headers: {
|
|
7797
|
+
...headers,
|
|
7798
|
+
...bearer ? {
|
|
7799
|
+
Authorization: `Bearer ${bearer}`
|
|
7800
|
+
} : {}
|
|
7801
|
+
}
|
|
7802
|
+
}), "send");
|
|
7803
|
+
let answer = await send(tokens.get(repository.path));
|
|
7804
|
+
if (answer.status === 401) answer = await send(await token(repository, answer.headers.get("www-authenticate")));
|
|
7805
|
+
return answer;
|
|
7806
|
+
}
|
|
7807
|
+
__name(call, "call");
|
|
7808
|
+
async function pushBlob(repository, bytes) {
|
|
7809
|
+
const digest = sha256(bytes);
|
|
7810
|
+
if ((await call(repository, "HEAD", `blobs/${digest}`)).ok) return digest;
|
|
7811
|
+
const started = await call(repository, "POST", "blobs/uploads/");
|
|
7812
|
+
if (started.status !== 202) throw new Error(`${repository.host} refused an upload: HTTP ${started.status}`);
|
|
7813
|
+
const location = new URL(started.headers.get("location") ?? "", `${origin(repository.host)}/`);
|
|
7814
|
+
location.searchParams.set("digest", digest);
|
|
7815
|
+
const put = await call(repository, "PUT", location.toString(), {
|
|
7816
|
+
headers: {
|
|
7817
|
+
"Content-Type": "application/octet-stream",
|
|
7818
|
+
"Content-Length": String(bytes.length)
|
|
7819
|
+
},
|
|
7820
|
+
body: bytes
|
|
7821
|
+
});
|
|
7822
|
+
if (put.status !== 201) throw new Error(`${repository.host} rejected blob ${digest}: HTTP ${put.status} ${await put.text()}`);
|
|
7823
|
+
return digest;
|
|
7824
|
+
}
|
|
7825
|
+
__name(pushBlob, "pushBlob");
|
|
7826
|
+
async function manifestExists(repository, digest) {
|
|
7827
|
+
const answer = await call(repository, "HEAD", `manifests/${digest}`, {
|
|
7828
|
+
headers: {
|
|
7829
|
+
Accept: OCI_MANIFEST
|
|
7830
|
+
}
|
|
7831
|
+
});
|
|
7832
|
+
return answer.ok;
|
|
7833
|
+
}
|
|
7834
|
+
__name(manifestExists, "manifestExists");
|
|
7835
|
+
async function pushArtifact(repository, artifact, tag) {
|
|
7836
|
+
await pushBlob(repository, EMPTY_CONFIG);
|
|
7837
|
+
await pushBlob(repository, artifact.documentBytes);
|
|
7838
|
+
for (const reference of [
|
|
7839
|
+
artifact.manifestDigest,
|
|
7840
|
+
tag
|
|
7841
|
+
]) {
|
|
7842
|
+
const put = await call(repository, "PUT", `manifests/${reference}`, {
|
|
7843
|
+
headers: {
|
|
7844
|
+
"Content-Type": OCI_MANIFEST
|
|
7845
|
+
},
|
|
7846
|
+
body: artifact.manifestBytes
|
|
7847
|
+
});
|
|
7848
|
+
if (put.status !== 201) {
|
|
7849
|
+
throw new Error(`${repository.host} rejected the manifest (${reference}): HTTP ${put.status} ${await put.text()}`);
|
|
7850
|
+
}
|
|
7851
|
+
}
|
|
7852
|
+
const asked = await call(repository, "HEAD", `manifests/${tag}`, {
|
|
7853
|
+
headers: {
|
|
7854
|
+
Accept: OCI_MANIFEST
|
|
7855
|
+
}
|
|
7856
|
+
});
|
|
7857
|
+
const reported = asked.headers.get("docker-content-digest");
|
|
7858
|
+
if (!asked.ok || !reported) {
|
|
7859
|
+
throw new Error(`${repository.host} could not say what :${tag} resolves to (HTTP ${asked.status}).`);
|
|
7860
|
+
}
|
|
7861
|
+
if (reported !== artifact.manifestDigest) {
|
|
7862
|
+
throw new Error(`${repository.host} reports :${tag} as ${reported}, but the bytes sent hash to ${artifact.manifestDigest}. Something re-encoded the manifest; nothing printed here would name what is stored. Refusing to report a digest.`);
|
|
7863
|
+
}
|
|
7864
|
+
return reported;
|
|
7865
|
+
}
|
|
7866
|
+
__name(pushArtifact, "pushArtifact");
|
|
7867
|
+
var defaultTag = /* @__PURE__ */ __name(() => (/* @__PURE__ */ new Date()).toISOString().replace(/[-:]/g, "").replace(/\..*$/, "").toLowerCase(), "defaultTag");
|
|
7868
|
+
|
|
7869
|
+
// src/catalog/flags.ts
|
|
7870
|
+
function parseCatalogFlags(argv, known, repeated = []) {
|
|
7871
|
+
const single = {};
|
|
7872
|
+
const many = {};
|
|
7873
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
7874
|
+
const argument = argv[index];
|
|
7875
|
+
const separator = argument.indexOf("=");
|
|
7876
|
+
const name = separator === -1 ? argument.slice(2) : argument.slice(2, separator);
|
|
7877
|
+
if (!argument.startsWith("--") || !known.includes(name)) throw new Error(`Unknown argument: ${argument}`);
|
|
7878
|
+
let value;
|
|
7879
|
+
if (separator !== -1) {
|
|
7880
|
+
value = argument.slice(separator + 1);
|
|
7881
|
+
} else {
|
|
7882
|
+
value = argv[index + 1];
|
|
7883
|
+
index += 1;
|
|
7884
|
+
}
|
|
7885
|
+
if (value === void 0 || value === "" || value.startsWith("--")) throw new Error(`--${name} needs a value.`);
|
|
7886
|
+
if (repeated.includes(name)) (many[name] ??= []).push(value);
|
|
7887
|
+
else single[name] = value;
|
|
7888
|
+
}
|
|
7889
|
+
return {
|
|
7890
|
+
single,
|
|
7891
|
+
many
|
|
7892
|
+
};
|
|
7893
|
+
}
|
|
7894
|
+
__name(parseCatalogFlags, "parseCatalogFlags");
|
|
7895
|
+
|
|
7896
|
+
// src/catalog/publish-action.ts
|
|
7897
|
+
var PUBLISH_ACTION_USAGE = "runveric catalog publish-action --manifest <file.yaml> --to <registry>/<namespace>/<repository>\n [--tag <tag>] [--repository <source url>] [--commit <sha>]";
|
|
7898
|
+
var isMapping = /* @__PURE__ */ __name((value) => typeof value === "object" && value !== null && !Array.isArray(value), "isMapping");
|
|
7899
|
+
async function runPublishAction(argv) {
|
|
7900
|
+
const { single: flags } = parseCatalogFlags(argv, [
|
|
7901
|
+
"manifest",
|
|
7902
|
+
"to",
|
|
7903
|
+
"tag",
|
|
7904
|
+
"repository",
|
|
7905
|
+
"commit"
|
|
7906
|
+
]);
|
|
7907
|
+
if (!flags.manifest || !flags.to) throw new Error("--manifest and --to are required.");
|
|
7908
|
+
const repository = parseRepository(flags.to, "--to");
|
|
7909
|
+
const path = resolve(flags.manifest);
|
|
7910
|
+
const manifest = readFileSync(path, "utf8");
|
|
7911
|
+
let parsed;
|
|
7912
|
+
try {
|
|
7913
|
+
parsed = parseYaml(manifest);
|
|
7914
|
+
} catch (cause) {
|
|
7915
|
+
throw new Error(`${flags.manifest} is not valid YAML. (${cause instanceof Error ? cause.message : String(cause)})`);
|
|
7916
|
+
}
|
|
7917
|
+
const fields = isMapping(parsed) ? parsed : {};
|
|
7918
|
+
const key = typeof fields.key === "string" && fields.key.length > 0 ? fields.key : null;
|
|
7919
|
+
if (key === null) throw new Error(`${flags.manifest} declares no top-level \`key:\` \u2014 is it a catalog manifest?`);
|
|
7920
|
+
const misnamed = (0, import_contracts2.actionPackageRefusal)(key, repository.ref);
|
|
7921
|
+
if (misnamed !== null) throw new Error(`--to: ${misnamed}`);
|
|
7922
|
+
let tag;
|
|
7923
|
+
if (fields.declares === "definition+version") {
|
|
7924
|
+
const version2 = typeof fields.version === "string" ? fields.version : null;
|
|
7925
|
+
if (version2 === null) throw new Error(`${flags.manifest} declares "definition+version" and no version:.`);
|
|
7926
|
+
if (flags.tag !== void 0 && flags.tag !== version2) {
|
|
7927
|
+
throw new Error(`${flags.manifest} declares version ${version2}, and the tag is ${flags.tag}. Tag the commit ${version2}, or change version: in ${flags.manifest} first.`);
|
|
7928
|
+
}
|
|
7929
|
+
tag = version2;
|
|
7930
|
+
} else {
|
|
7931
|
+
tag = flags.tag ?? defaultTag();
|
|
7932
|
+
}
|
|
7933
|
+
requireTag(tag, flags.tag !== void 0 ? "--tag" : `${flags.manifest}'s version`);
|
|
7934
|
+
const artifact = buildArtifact({
|
|
7935
|
+
schemaVersion: import_contracts2.CATALOG_ACTION_ARTIFACT_SCHEMA_V1,
|
|
7936
|
+
manifest,
|
|
7937
|
+
provenance: provenance(flags, dirname(path))
|
|
7938
|
+
});
|
|
7939
|
+
const digest = await pushArtifact(repository, artifact, tag);
|
|
7940
|
+
process.stderr.write(`\u2713 ${key} published to ${repository.ref}:${tag}
|
|
7941
|
+
`);
|
|
7942
|
+
process.stderr.write(` the registry reports ${digest} \u2014 the digest a release must name.
|
|
7943
|
+
`);
|
|
7944
|
+
process.stdout.write(`${key}=${repository.ref}@${digest}
|
|
7945
|
+
`);
|
|
7946
|
+
}
|
|
7947
|
+
__name(runPublishAction, "runPublishAction");
|
|
7948
|
+
|
|
7949
|
+
// src/catalog/publish-release.ts
|
|
7950
|
+
var import_contracts3 = __toESM(require_dist());
|
|
7951
|
+
import { readFileSync as readFileSync2 } from "fs";
|
|
7952
|
+
import { parse as parseYaml2 } from "yaml";
|
|
7953
|
+
var PUBLISH_RELEASE_USAGE = "runveric catalog publish-release (--from <release.yaml> | --action <key>=<repository>@<digest> \u2026)\n --to <registry>/<namespace>/<repository> [--version <label>]\n [--tag <tag>] [--repository <source url>] [--commit <sha>]";
|
|
7954
|
+
function entriesFromFlags(values) {
|
|
7955
|
+
return values.map((value) => {
|
|
7956
|
+
const match = /^([^=]+)=([^@]+)@(.+)$/.exec(value);
|
|
7957
|
+
if (!match) throw new Error(`--action "${value}" is not <key>=<repository>@<digest>.`);
|
|
7958
|
+
const [, key = "", artifactRef = "", digest = ""] = match;
|
|
7959
|
+
return {
|
|
7960
|
+
key,
|
|
7961
|
+
artifactRef,
|
|
7962
|
+
digest,
|
|
7963
|
+
label: `--action ${key}`
|
|
7964
|
+
};
|
|
7965
|
+
});
|
|
7966
|
+
}
|
|
7967
|
+
__name(entriesFromFlags, "entriesFromFlags");
|
|
7968
|
+
function specFromFile(path) {
|
|
7969
|
+
let value;
|
|
7970
|
+
try {
|
|
7971
|
+
value = parseYaml2(readFileSync2(path, "utf8"));
|
|
7972
|
+
} catch (cause) {
|
|
7973
|
+
throw new Error(`--from ${path} could not be read as YAML. (${cause instanceof Error ? cause.message : String(cause)})`);
|
|
7974
|
+
}
|
|
7975
|
+
const spec = (0, import_contracts3.parseCatalogReleaseSpec)(value);
|
|
7976
|
+
return {
|
|
7977
|
+
version: spec.version,
|
|
7978
|
+
entries: spec.actions.map((action) => ({
|
|
7979
|
+
...action,
|
|
7980
|
+
label: `${path}'s ${action.key}`
|
|
7981
|
+
}))
|
|
7982
|
+
};
|
|
7983
|
+
}
|
|
7984
|
+
__name(specFromFile, "specFromFile");
|
|
7985
|
+
async function runPublishRelease(argv) {
|
|
7986
|
+
const { single: flags, many } = parseCatalogFlags(argv, [
|
|
7987
|
+
"to",
|
|
7988
|
+
"version",
|
|
7989
|
+
"action",
|
|
7990
|
+
"from",
|
|
7991
|
+
"tag",
|
|
7992
|
+
"repository",
|
|
7993
|
+
"commit"
|
|
7994
|
+
], [
|
|
7995
|
+
"action"
|
|
7996
|
+
]);
|
|
7997
|
+
const actionFlags = many.action ?? [];
|
|
7998
|
+
if (flags.from !== void 0 && actionFlags.length > 0) {
|
|
7999
|
+
throw new Error("--from and --action are alternatives: name the release's actions in release.yaml or as flags, not both.");
|
|
8000
|
+
}
|
|
8001
|
+
if (flags.from !== void 0 && flags.version !== void 0) {
|
|
8002
|
+
throw new Error("--version is read from release.yaml when --from is given; pass one or the other.");
|
|
8003
|
+
}
|
|
8004
|
+
if (!flags.to || flags.from === void 0 && (!flags.version || actionFlags.length === 0)) {
|
|
8005
|
+
throw new Error("--to and either --from, or --version and at least one --action, are required.");
|
|
8006
|
+
}
|
|
8007
|
+
const release = parseRepository(flags.to, "--to");
|
|
8008
|
+
const { version: version2, entries } = flags.from !== void 0 ? specFromFile(flags.from) : {
|
|
8009
|
+
version: flags.version,
|
|
8010
|
+
entries: entriesFromFlags(actionFlags)
|
|
8011
|
+
};
|
|
8012
|
+
const tag = flags.tag ?? (flags.from !== void 0 ? version2 : defaultTag());
|
|
8013
|
+
requireTag(tag, flags.tag !== void 0 ? "--tag" : `${flags.from}'s version`);
|
|
8014
|
+
const seen = /* @__PURE__ */ new Set();
|
|
8015
|
+
const actions = entries.map((entry) => {
|
|
8016
|
+
if (seen.has(entry.key)) throw new Error(`${entry.label} names "${entry.key}" twice.`);
|
|
8017
|
+
seen.add(entry.key);
|
|
8018
|
+
const repository = parseRepository(entry.artifactRef, entry.label);
|
|
8019
|
+
if (repository.namespace !== release.namespace) {
|
|
8020
|
+
throw new Error(`${entry.label} lives in "${repository.namespace}", outside the release's namespace "${release.namespace}". The server refuses a release that sends it to another host or org.`);
|
|
8021
|
+
}
|
|
8022
|
+
if (!isDigest(entry.digest)) {
|
|
8023
|
+
throw new Error(`${entry.label}: "${entry.digest}" is not a digest. A release names artifacts by digest only.`);
|
|
8024
|
+
}
|
|
8025
|
+
const misnamed = (0, import_contracts3.actionPackageRefusal)(entry.key, entry.artifactRef);
|
|
8026
|
+
if (misnamed !== null) throw new Error(`${entry.label}: ${misnamed}`);
|
|
8027
|
+
return {
|
|
8028
|
+
...entry,
|
|
8029
|
+
repository
|
|
8030
|
+
};
|
|
8031
|
+
});
|
|
8032
|
+
for (const action of actions) {
|
|
8033
|
+
if (!await manifestExists(action.repository, action.digest)) {
|
|
8034
|
+
throw new Error(`${action.artifactRef}@${action.digest} (${action.key}) is not in the registry.`);
|
|
8035
|
+
}
|
|
8036
|
+
}
|
|
8037
|
+
const artifact = buildArtifact({
|
|
8038
|
+
schemaVersion: import_contracts3.CATALOG_RELEASE_SCHEMA_V1,
|
|
8039
|
+
version: version2,
|
|
8040
|
+
provenance: provenance(flags, process.cwd()),
|
|
8041
|
+
actions: actions.map(({ key, artifactRef, digest: digest2 }) => ({
|
|
8042
|
+
key,
|
|
8043
|
+
artifactRef,
|
|
8044
|
+
digest: digest2
|
|
8045
|
+
}))
|
|
8046
|
+
});
|
|
8047
|
+
const digest = await pushArtifact(release, artifact, tag);
|
|
8048
|
+
process.stderr.write(`\u2713 catalog release ${version2} (${actions.length} action artifact(s)) published to ${release.ref}:${tag}
|
|
8049
|
+
`);
|
|
8050
|
+
process.stderr.write(` the registry reports ${digest} \u2014 the digest to plan and pin.
|
|
8051
|
+
`);
|
|
8052
|
+
process.stdout.write(`${release.ref}@${digest}
|
|
8053
|
+
`);
|
|
8054
|
+
}
|
|
8055
|
+
__name(runPublishRelease, "runPublishRelease");
|
|
8056
|
+
|
|
8057
|
+
// src/catalog/index.ts
|
|
8058
|
+
var CATALOG_USAGE = `runveric catalog \u2014 publish first-party catalog artifacts (docs/127)
|
|
8059
|
+
|
|
8060
|
+
${PUBLISH_ACTION_USAGE}
|
|
8061
|
+
Publish one action's manifest, verbatim, as an artifact. stdout: <key>=<repository>@<digest>
|
|
8062
|
+
|
|
8063
|
+
${PUBLISH_RELEASE_USAGE}
|
|
8064
|
+
Publish a release naming each action artifact by digest. stdout: <repository>@<digest>
|
|
8065
|
+
|
|
8066
|
+
Credentials: GHCR_TOKEN (write:packages), or in a workflow GITHUB_TOKEN with packages: write.
|
|
8067
|
+
Provenance: --repository/--commit, else GITHUB_SERVER_URL/GITHUB_REPOSITORY and GITHUB_SHA, else git.`;
|
|
8068
|
+
var SUBCOMMANDS = {
|
|
8069
|
+
"publish-action": runPublishAction,
|
|
8070
|
+
"publish-release": runPublishRelease
|
|
8071
|
+
};
|
|
8072
|
+
async function runCatalog(argv) {
|
|
8073
|
+
const [subcommand, ...rest] = argv;
|
|
8074
|
+
if (subcommand === void 0 || subcommand === "--help" || rest.includes("--help")) {
|
|
8075
|
+
process.stdout.write(`${CATALOG_USAGE}
|
|
8076
|
+
`);
|
|
8077
|
+
return subcommand === void 0 ? 1 : 0;
|
|
8078
|
+
}
|
|
8079
|
+
const run3 = SUBCOMMANDS[subcommand];
|
|
8080
|
+
if (run3 === void 0) {
|
|
8081
|
+
printError(`\u2717 "catalog ${subcommand}" is not a command. There are two: ${Object.keys(SUBCOMMANDS).join(", ")}.`);
|
|
8082
|
+
return 1;
|
|
8083
|
+
}
|
|
8084
|
+
try {
|
|
8085
|
+
await run3(rest);
|
|
8086
|
+
return 0;
|
|
8087
|
+
} catch (error) {
|
|
8088
|
+
printError(`\u2717 ${error instanceof Error ? error.message : String(error)}`);
|
|
8089
|
+
return 1;
|
|
8090
|
+
}
|
|
8091
|
+
}
|
|
8092
|
+
__name(runCatalog, "runCatalog");
|
|
8093
|
+
|
|
8094
|
+
// src/check.ts
|
|
8095
|
+
var import_action_manifest = __toESM(require_dist2());
|
|
8096
|
+
import { resolve as resolve2 } from "path";
|
|
8097
|
+
|
|
8098
|
+
// src/package-dir.ts
|
|
8099
|
+
import { readdir, readFile, stat } from "fs/promises";
|
|
8100
|
+
import { join, relative, sep } from "path";
|
|
8101
|
+
var IGNORED_DIRECTORIES = /* @__PURE__ */ new Set([
|
|
8102
|
+
".git",
|
|
8103
|
+
".runveric",
|
|
8104
|
+
"node_modules",
|
|
8105
|
+
".venv",
|
|
8106
|
+
"__pycache__",
|
|
8107
|
+
".DS_Store"
|
|
8108
|
+
]);
|
|
8109
|
+
var MAX_FILES = 2e3;
|
|
8110
|
+
var MAX_TOTAL_BYTES = 16 * 1024 * 1024;
|
|
8111
|
+
var PackageDirectoryError = class extends Error {
|
|
8112
|
+
static {
|
|
8113
|
+
__name(this, "PackageDirectoryError");
|
|
8114
|
+
}
|
|
8115
|
+
};
|
|
8116
|
+
async function readPackageDirectory(root) {
|
|
8117
|
+
const properties = await stat(root).catch(() => null);
|
|
8118
|
+
if (!properties?.isDirectory()) {
|
|
8119
|
+
throw new PackageDirectoryError(`${root} is not a directory.`);
|
|
8120
|
+
}
|
|
8121
|
+
const files = /* @__PURE__ */ new Map();
|
|
8122
|
+
let totalBytes = 0;
|
|
8123
|
+
const walk = /* @__PURE__ */ __name(async (directory) => {
|
|
8124
|
+
for (const entry of await readdir(directory, {
|
|
8125
|
+
withFileTypes: true
|
|
8126
|
+
})) {
|
|
8127
|
+
if (IGNORED_DIRECTORIES.has(entry.name)) continue;
|
|
8128
|
+
const full = join(directory, entry.name);
|
|
8129
|
+
if (entry.isDirectory()) {
|
|
8130
|
+
await walk(full);
|
|
8131
|
+
continue;
|
|
8132
|
+
}
|
|
8133
|
+
if (!entry.isFile()) continue;
|
|
8134
|
+
if (files.size >= MAX_FILES) {
|
|
8135
|
+
throw new PackageDirectoryError(`This directory holds more than ${MAX_FILES} files. That is almost certainly not a single action package \u2014 run this from the package directory itself.`);
|
|
8136
|
+
}
|
|
8137
|
+
const contents = await readFile(full);
|
|
8138
|
+
totalBytes += contents.byteLength;
|
|
8139
|
+
if (totalBytes > MAX_TOTAL_BYTES) {
|
|
8140
|
+
throw new PackageDirectoryError(`This directory holds more than ${MAX_TOTAL_BYTES / (1024 * 1024)}MB. An action package is source, not artifacts \u2014 add build output to .gitignore.`);
|
|
8141
|
+
}
|
|
8142
|
+
files.set(toPackagePath(root, full), contents);
|
|
8143
|
+
}
|
|
8144
|
+
}, "walk");
|
|
8145
|
+
await walk(root);
|
|
8146
|
+
return files;
|
|
8147
|
+
}
|
|
8148
|
+
__name(readPackageDirectory, "readPackageDirectory");
|
|
8149
|
+
function toPackagePath(root, full) {
|
|
8150
|
+
return relative(root, full).split(sep).join("/");
|
|
8151
|
+
}
|
|
8152
|
+
__name(toPackagePath, "toPackagePath");
|
|
8153
|
+
|
|
8154
|
+
// src/check.ts
|
|
8155
|
+
var import_contracts4 = __toESM(require_dist());
|
|
7115
8156
|
async function runCheck(options) {
|
|
7116
|
-
const directory =
|
|
8157
|
+
const directory = resolve2(options.directory ?? ".");
|
|
7117
8158
|
let files;
|
|
7118
8159
|
try {
|
|
7119
8160
|
files = await readPackageDirectory(directory);
|
|
@@ -7135,7 +8176,7 @@ async function runCheck(options) {
|
|
|
7135
8176
|
print(style.red("This package would be REFUSED at import."));
|
|
7136
8177
|
} else if (report.lintBlocked) {
|
|
7137
8178
|
print();
|
|
7138
|
-
print(style.red("This package would be ACCEPTED at import \u2014 and then misbehave.") + ` The errors above are not things ${
|
|
8179
|
+
print(style.red("This package would be ACCEPTED at import \u2014 and then misbehave.") + ` The errors above are not things ${import_contracts4.BRAND_SHORT_NAME} checks; they are things that go wrong at run time, silently.`);
|
|
7139
8180
|
}
|
|
7140
8181
|
if (report.advisoryCount > 0) {
|
|
7141
8182
|
print();
|
|
@@ -7155,11 +8196,11 @@ async function runCheck(options) {
|
|
|
7155
8196
|
__name(runCheck, "runCheck");
|
|
7156
8197
|
|
|
7157
8198
|
// src/init.ts
|
|
7158
|
-
var
|
|
8199
|
+
var import_contracts5 = __toESM(require_dist());
|
|
7159
8200
|
var import_action_manifest2 = __toESM(require_dist2());
|
|
7160
8201
|
import { mkdir, writeFile } from "fs/promises";
|
|
7161
8202
|
import { createInterface } from "readline/promises";
|
|
7162
|
-
import { dirname, join as join2, resolve as
|
|
8203
|
+
import { dirname as dirname2, join as join2, resolve as resolve3 } from "path";
|
|
7163
8204
|
async function runInit(options) {
|
|
7164
8205
|
const interactive = process.stdin.isTTY === true && options.yes !== true;
|
|
7165
8206
|
const ask = interactive ? prompter() : null;
|
|
@@ -7171,7 +8212,7 @@ async function runInit(options) {
|
|
|
7171
8212
|
const interpreter = await resolveInterpreter(options.interpreter, ask);
|
|
7172
8213
|
if (!interpreter) return 1;
|
|
7173
8214
|
const author = options.author?.trim() || await ask?.("Author", id.split("/")[0]) || id.split("/")[0];
|
|
7174
|
-
const directory =
|
|
8215
|
+
const directory = resolve3(options.directory ?? id.split("/")[1] ?? "action");
|
|
7175
8216
|
const files = (0, import_action_manifest2.scaffoldActionPackage)({
|
|
7176
8217
|
id,
|
|
7177
8218
|
name,
|
|
@@ -7181,7 +8222,7 @@ async function runInit(options) {
|
|
|
7181
8222
|
});
|
|
7182
8223
|
for (const [path, contents] of files) {
|
|
7183
8224
|
const target = join2(directory, path);
|
|
7184
|
-
await mkdir(
|
|
8225
|
+
await mkdir(dirname2(target), {
|
|
7185
8226
|
recursive: true
|
|
7186
8227
|
});
|
|
7187
8228
|
await writeFile(target, contents, {
|
|
@@ -7224,9 +8265,9 @@ async function resolveId(supplied, ask) {
|
|
|
7224
8265
|
}
|
|
7225
8266
|
__name(resolveId, "resolveId");
|
|
7226
8267
|
async function resolveInterpreter(supplied, ask) {
|
|
7227
|
-
const value = supplied?.trim() || await ask?.(`Interpreter (${
|
|
8268
|
+
const value = supplied?.trim() || await ask?.(`Interpreter (${import_contracts5.PACKAGE_INTERPRETERS.join(" / ")})`, "bash") || "bash";
|
|
7228
8269
|
if (!isInterpreter(value)) {
|
|
7229
|
-
printError(style.red(`"${value}" is not an interpreter ${
|
|
8270
|
+
printError(style.red(`"${value}" is not an interpreter ${import_contracts5.BRAND_SHORT_NAME} runs.`) + ` The runner image ships ${import_contracts5.PACKAGE_INTERPRETERS.join(", ")}.`);
|
|
7230
8271
|
return null;
|
|
7231
8272
|
}
|
|
7232
8273
|
return value;
|
|
@@ -7247,7 +8288,7 @@ function prompter() {
|
|
|
7247
8288
|
}
|
|
7248
8289
|
__name(prompter, "prompter");
|
|
7249
8290
|
function isInterpreter(value) {
|
|
7250
|
-
return
|
|
8291
|
+
return import_contracts5.PACKAGE_INTERPRETERS.includes(value);
|
|
7251
8292
|
}
|
|
7252
8293
|
__name(isInterpreter, "isInterpreter");
|
|
7253
8294
|
function titleCase(value) {
|
|
@@ -7257,8 +8298,8 @@ __name(titleCase, "titleCase");
|
|
|
7257
8298
|
|
|
7258
8299
|
// src/publish.ts
|
|
7259
8300
|
var import_action_manifest3 = __toESM(require_dist2());
|
|
7260
|
-
var
|
|
7261
|
-
import { resolve as
|
|
8301
|
+
var import_contracts6 = __toESM(require_dist());
|
|
8302
|
+
import { resolve as resolve4 } from "path";
|
|
7262
8303
|
|
|
7263
8304
|
// src/renamed-variable.ts
|
|
7264
8305
|
function renamedVariableRefusal(current, retired, env = process.env) {
|
|
@@ -7269,15 +8310,15 @@ function renamedVariableRefusal(current, retired, env = process.env) {
|
|
|
7269
8310
|
__name(renamedVariableRefusal, "renamedVariableRefusal");
|
|
7270
8311
|
|
|
7271
8312
|
// src/publish.ts
|
|
7272
|
-
var TOKEN_ENV =
|
|
7273
|
-
var URL_ENV =
|
|
8313
|
+
var TOKEN_ENV = import_contracts6.AUTHORING_CLI_ENV.token;
|
|
8314
|
+
var URL_ENV = import_contracts6.AUTHORING_CLI_ENV.url;
|
|
7274
8315
|
async function runPublish(options) {
|
|
7275
|
-
const directory =
|
|
8316
|
+
const directory = resolve4(options.directory ?? ".");
|
|
7276
8317
|
const baseUrl = (options.to ?? process.env[URL_ENV] ?? "").trim().replace(/\/+$/, "");
|
|
7277
|
-
const
|
|
8318
|
+
const token2 = (options.token ?? process.env[TOKEN_ENV] ?? "").trim();
|
|
7278
8319
|
const stale = [
|
|
7279
|
-
options.to === void 0 ? renamedVariableRefusal(URL_ENV,
|
|
7280
|
-
options.token === void 0 ? renamedVariableRefusal(TOKEN_ENV,
|
|
8320
|
+
options.to === void 0 ? renamedVariableRefusal(URL_ENV, import_contracts6.RETIRED_AUTHORING_CLI_ENV.url) : null,
|
|
8321
|
+
options.token === void 0 ? renamedVariableRefusal(TOKEN_ENV, import_contracts6.RETIRED_AUTHORING_CLI_ENV.token) : null
|
|
7281
8322
|
].filter((sentence) => sentence !== null);
|
|
7282
8323
|
if (stale.length > 0) {
|
|
7283
8324
|
for (const sentence of stale) printError(style.red(sentence));
|
|
@@ -7287,8 +8328,8 @@ async function runPublish(options) {
|
|
|
7287
8328
|
printError(style.red("Where to?") + ` Pass --to https://your-runveric.example.com, or set ${URL_ENV}.`);
|
|
7288
8329
|
return 1;
|
|
7289
8330
|
}
|
|
7290
|
-
if (!
|
|
7291
|
-
printError(style.red(`Publishing needs ${
|
|
8331
|
+
if (!token2) {
|
|
8332
|
+
printError(style.red(`Publishing needs ${import_contracts6.BRAND_ARTICLE} ${import_contracts6.BRAND_SHORT_NAME} access token.`) + ` Set ${TOKEN_ENV}, or pass --token. (init, check and test need no account at all.)`);
|
|
7292
8333
|
return 1;
|
|
7293
8334
|
}
|
|
7294
8335
|
let files;
|
|
@@ -7308,7 +8349,7 @@ async function runPublish(options) {
|
|
|
7308
8349
|
errors: report.errorCount,
|
|
7309
8350
|
warnings: report.warningCount
|
|
7310
8351
|
});
|
|
7311
|
-
printError(style.red("\nNot published.") + (report.validation.ok ? ` ${
|
|
8352
|
+
printError(style.red("\nNot published.") + (report.validation.ok ? ` ${import_contracts6.BRAND_SHORT_NAME} would accept this, but the problems above make it misbehave at run time. Fix them, or pass --force if you disagree.` : " Fix the errors above and publish again."));
|
|
7312
8353
|
return 1;
|
|
7313
8354
|
}
|
|
7314
8355
|
if (report.advisoryCount > 0) {
|
|
@@ -7335,7 +8376,7 @@ async function runPublish(options) {
|
|
|
7335
8376
|
method: "POST",
|
|
7336
8377
|
headers: {
|
|
7337
8378
|
"content-type": "application/json",
|
|
7338
|
-
authorization: `Bearer ${
|
|
8379
|
+
authorization: `Bearer ${token2}`
|
|
7339
8380
|
},
|
|
7340
8381
|
body
|
|
7341
8382
|
});
|
|
@@ -7355,7 +8396,7 @@ Publish refused (${response.status}).`));
|
|
|
7355
8396
|
try {
|
|
7356
8397
|
version2 = JSON.parse(text);
|
|
7357
8398
|
} catch {
|
|
7358
|
-
printError(style.red(`${
|
|
8399
|
+
printError(style.red(`${import_contracts6.BRAND_SHORT_NAME} accepted the package but returned a response we cannot read.`));
|
|
7359
8400
|
return 1;
|
|
7360
8401
|
}
|
|
7361
8402
|
print();
|
|
@@ -7364,7 +8405,7 @@ Publish refused (${response.status}).`));
|
|
|
7364
8405
|
print(` content digest ${version2.contentDigest}`);
|
|
7365
8406
|
print(` tier ${version2.tier} ${style.grey(`(${version2.provenance})`)}`);
|
|
7366
8407
|
print();
|
|
7367
|
-
print(style.grey(`It is an immutable version now. Adopt it in ${
|
|
8408
|
+
print(style.grey(`It is an immutable version now. Adopt it in ${import_contracts6.BRAND_SHORT_NAME} to put it in the catalog \u2014 publishing does not adopt, so nobody can run it until somebody chooses to.`));
|
|
7368
8409
|
print();
|
|
7369
8410
|
return 0;
|
|
7370
8411
|
}
|
|
@@ -7376,11 +8417,11 @@ function formatProblem(text) {
|
|
|
7376
8417
|
} catch {
|
|
7377
8418
|
return ` ${text}`;
|
|
7378
8419
|
}
|
|
7379
|
-
const problem = (0,
|
|
8420
|
+
const problem = (0, import_contracts6.parseProblemDocument)(parsed);
|
|
7380
8421
|
if (!problem) return ` ${text}`;
|
|
7381
8422
|
const lines = [];
|
|
7382
8423
|
if (problem.detail) lines.push(` ${problem.detail}`);
|
|
7383
|
-
for (const error of (0,
|
|
8424
|
+
for (const error of (0, import_contracts6.problemFieldErrors)(problem)) {
|
|
7384
8425
|
lines.push(error.field ? ` ${style.bold(error.field)}: ${error.message}` : ` ${error.message}`);
|
|
7385
8426
|
}
|
|
7386
8427
|
return lines.length > 0 ? lines.join("\n") : ` ${text}`;
|
|
@@ -7388,12 +8429,12 @@ function formatProblem(text) {
|
|
|
7388
8429
|
__name(formatProblem, "formatProblem");
|
|
7389
8430
|
|
|
7390
8431
|
// src/runner-image.ts
|
|
7391
|
-
var
|
|
8432
|
+
var import_contracts7 = __toESM(require_dist());
|
|
7392
8433
|
import { execFile } from "child_process";
|
|
7393
8434
|
import { promisify } from "util";
|
|
7394
8435
|
var run = promisify(execFile);
|
|
7395
8436
|
var LOCAL_RUNNER_IMAGE = "runveric-package-runner:local";
|
|
7396
|
-
var RUNNER_IMAGE_ENV =
|
|
8437
|
+
var RUNNER_IMAGE_ENV = import_contracts7.AUTHORING_CLI_ENV.runnerImage;
|
|
7397
8438
|
var RenamedVariableError = class extends Error {
|
|
7398
8439
|
static {
|
|
7399
8440
|
__name(this, "RenamedVariableError");
|
|
@@ -7410,7 +8451,7 @@ function resolveRunnerImage(flag) {
|
|
|
7410
8451
|
reference: configured,
|
|
7411
8452
|
origin: "environment"
|
|
7412
8453
|
};
|
|
7413
|
-
const stale = renamedVariableRefusal(RUNNER_IMAGE_ENV,
|
|
8454
|
+
const stale = renamedVariableRefusal(RUNNER_IMAGE_ENV, import_contracts7.RETIRED_AUTHORING_CLI_ENV.runnerImage);
|
|
7414
8455
|
if (stale) throw new RenamedVariableError(stale);
|
|
7415
8456
|
return {
|
|
7416
8457
|
reference: LOCAL_RUNNER_IMAGE,
|
|
@@ -7425,7 +8466,7 @@ function runnerImageNote(image) {
|
|
|
7425
8466
|
case "environment":
|
|
7426
8467
|
return `from ${RUNNER_IMAGE_ENV}`;
|
|
7427
8468
|
case "local-build":
|
|
7428
|
-
return `locally built \u2014 NOT the image your ${
|
|
8469
|
+
return `locally built \u2014 NOT the image your ${import_contracts7.BRAND_SHORT_NAME} runs; set ${RUNNER_IMAGE_ENV} to match it`;
|
|
7429
8470
|
}
|
|
7430
8471
|
}
|
|
7431
8472
|
__name(runnerImageNote, "runnerImageNote");
|
|
@@ -7442,7 +8483,7 @@ async function assertDockerAvailable() {
|
|
|
7442
8483
|
"{{.Server.Version}}"
|
|
7443
8484
|
]);
|
|
7444
8485
|
} catch {
|
|
7445
|
-
throw new DockerMissingError(`Docker is not available. \`runveric test\` runs your package in the real ${
|
|
8486
|
+
throw new DockerMissingError(`Docker is not available. \`runveric test\` runs your package in the real ${import_contracts7.BRAND_SHORT_NAME} runner image, which needs a container runtime \u2014 install Docker Desktop (or start it), then try again. \`runveric check\` needs nothing and still works.`);
|
|
7446
8487
|
}
|
|
7447
8488
|
}
|
|
7448
8489
|
__name(assertDockerAvailable, "assertDockerAvailable");
|
|
@@ -7465,7 +8506,7 @@ var import_action_manifest4 = __toESM(require_dist2());
|
|
|
7465
8506
|
import { spawn } from "child_process";
|
|
7466
8507
|
import { mkdir as mkdir2, mkdtemp, readFile as readFile2, rm, stat as stat2, writeFile as writeFile2 } from "fs/promises";
|
|
7467
8508
|
import { tmpdir } from "os";
|
|
7468
|
-
import { dirname as
|
|
8509
|
+
import { dirname as dirname3, join as join3, resolve as resolve5 } from "path";
|
|
7469
8510
|
import { StringDecoder } from "string_decoder";
|
|
7470
8511
|
|
|
7471
8512
|
// src/azure-credential.ts
|
|
@@ -7488,7 +8529,7 @@ async function acquireAzureCredential() {
|
|
|
7488
8529
|
if (!account.id || !account.tenantId) {
|
|
7489
8530
|
throw new AzureCredentialError("`az account show` returned no subscription. Run `az login` and `az account set --subscription <id>` first.");
|
|
7490
8531
|
}
|
|
7491
|
-
const
|
|
8532
|
+
const token2 = await azJson([
|
|
7492
8533
|
"account",
|
|
7493
8534
|
"get-access-token",
|
|
7494
8535
|
"--resource",
|
|
@@ -7496,11 +8537,11 @@ async function acquireAzureCredential() {
|
|
|
7496
8537
|
"--output",
|
|
7497
8538
|
"json"
|
|
7498
8539
|
]);
|
|
7499
|
-
if (!
|
|
8540
|
+
if (!token2.accessToken) {
|
|
7500
8541
|
throw new AzureCredentialError("`az account get-access-token` returned no access token.");
|
|
7501
8542
|
}
|
|
7502
8543
|
return {
|
|
7503
|
-
token:
|
|
8544
|
+
token: token2.accessToken,
|
|
7504
8545
|
// The identical names the credential adapter puts in a lease, so a package reads the same
|
|
7505
8546
|
// environment here and in production.
|
|
7506
8547
|
env: {
|
|
@@ -7535,7 +8576,7 @@ ${message.trim()}`);
|
|
|
7535
8576
|
__name(azJson, "azJson");
|
|
7536
8577
|
|
|
7537
8578
|
// src/test.ts
|
|
7538
|
-
var
|
|
8579
|
+
var import_contracts8 = __toESM(require_dist());
|
|
7539
8580
|
var PHASES = [
|
|
7540
8581
|
"validate",
|
|
7541
8582
|
"run",
|
|
@@ -7549,10 +8590,10 @@ var CONTAINER = {
|
|
|
7549
8590
|
creds: "/runveric/creds"
|
|
7550
8591
|
};
|
|
7551
8592
|
async function runTest(options) {
|
|
7552
|
-
const directory =
|
|
8593
|
+
const directory = resolve5(options.directory ?? ".");
|
|
7553
8594
|
const phase = options.phase ?? "run";
|
|
7554
8595
|
if (!PHASES.includes(phase)) {
|
|
7555
|
-
printError(style.red(`"${options.phase}" is not a phase.`) + ` ${
|
|
8596
|
+
printError(style.red(`"${options.phase}" is not a phase.`) + ` ${import_contracts8.BRAND_SHORT_NAME} runs ${PHASES.join(", ")} \u2014 one at a time, so you can read each one's result.`);
|
|
7556
8597
|
return 1;
|
|
7557
8598
|
}
|
|
7558
8599
|
let files;
|
|
@@ -7624,9 +8665,9 @@ async function runTest(options) {
|
|
|
7624
8665
|
print(` runner image ${image.reference} ${style.grey(`(${runnerImageNote(image)})`)}`);
|
|
7625
8666
|
print(` interpreter ${interpreter}@${manifest.runtime.version}`);
|
|
7626
8667
|
print(` entrypoint ${entrypoint}${import_action_manifest4.PACKAGE_INTERPRETER_LAUNCH[interpreter].entryFile}`);
|
|
7627
|
-
print(` identity ${credential ? `${credential.account.name} ${style.grey(`\u2014 YOUR access, not ${
|
|
8668
|
+
print(` identity ${credential ? `${credential.account.name} ${style.grey(`\u2014 YOUR access, not ${import_contracts8.BRAND_SHORT_NAME}'s brokered least-privilege identity`)}` : style.grey("none (--no-credential)")}`);
|
|
7628
8669
|
if (manifest.requiresNetwork) {
|
|
7629
|
-
print(` network ${style.yellow("open")} ${style.grey(`\u2014 your allowlist (${(manifest.egressAllowlist ?? []).join(", ")}) is NOT enforced here; ${
|
|
8670
|
+
print(` network ${style.yellow("open")} ${style.grey(`\u2014 your allowlist (${(manifest.egressAllowlist ?? []).join(", ")}) is NOT enforced here; ${import_contracts8.BRAND_SHORT_NAME} enforces it`)}`);
|
|
7630
8671
|
} else {
|
|
7631
8672
|
print(` network ${style.grey("none \u2014 this package declares requiresNetwork: false")}`);
|
|
7632
8673
|
}
|
|
@@ -7728,13 +8769,13 @@ async function materialize(workspace, input) {
|
|
|
7728
8769
|
})));
|
|
7729
8770
|
for (const [path, contents] of input.files) {
|
|
7730
8771
|
const target = join3(layout.packageRoot, path);
|
|
7731
|
-
await mkdir2(
|
|
8772
|
+
await mkdir2(dirname3(target), {
|
|
7732
8773
|
recursive: true
|
|
7733
8774
|
});
|
|
7734
8775
|
await writeFile2(target, contents);
|
|
7735
8776
|
}
|
|
7736
8777
|
const context = {
|
|
7737
|
-
protocolVersion:
|
|
8778
|
+
protocolVersion: import_contracts8.PACKAGE_EXECUTION_PROTOCOL_VERSION,
|
|
7738
8779
|
// A recognisable id rather than a random uuid: it appears in the package's own log lines,
|
|
7739
8780
|
// and "local-test" tells the reader instantly that this was not a real run.
|
|
7740
8781
|
executionId: "local-test",
|
|
@@ -7760,7 +8801,7 @@ async function runContainer(options) {
|
|
|
7760
8801
|
const launch = import_action_manifest4.PACKAGE_INTERPRETER_LAUNCH[options.interpreter];
|
|
7761
8802
|
const script = `${CONTAINER.packageRoot}/${options.entrypoint}${launch.entryFile}`;
|
|
7762
8803
|
const environment = {
|
|
7763
|
-
RUNVERIC_PROTOCOL_VERSION:
|
|
8804
|
+
RUNVERIC_PROTOCOL_VERSION: import_contracts8.PACKAGE_RESULT_PROTOCOL_VERSION,
|
|
7764
8805
|
RUNVERIC_PHASE: options.phase,
|
|
7765
8806
|
RUNVERIC_CONTEXT_FILE: `${CONTAINER.input}/context.json`,
|
|
7766
8807
|
RUNVERIC_PARAMETERS_FILE: `${CONTAINER.input}/parameters.json`,
|
|
@@ -7887,13 +8928,13 @@ function emitLine(line, stderr, onEvent) {
|
|
|
7887
8928
|
__name(emitLine, "emitLine");
|
|
7888
8929
|
async function reportOutcome(options) {
|
|
7889
8930
|
if (options.exit.timedOut) {
|
|
7890
|
-
printError(style.red("\nThe package did not finish within 15 minutes and was killed.") + ` ${
|
|
8931
|
+
printError(style.red("\nThe package did not finish within 15 minutes and was killed.") + ` ${import_contracts8.BRAND_SHORT_NAME} enforces the \`executionTimeout\` in your manifest; this is the local ceiling.`);
|
|
7891
8932
|
return 1;
|
|
7892
8933
|
}
|
|
7893
8934
|
const exists = await stat2(options.resultPath).catch(() => null);
|
|
7894
8935
|
if (!exists?.isFile() || exists.size === 0) {
|
|
7895
8936
|
printError(style.red("\nThe package wrote no result.") + `
|
|
7896
|
-
result.json is the only channel ${
|
|
8937
|
+
result.json is the only channel ${import_contracts8.BRAND_SHORT_NAME} reads. Exiting ${options.exit.code ?? "with a signal"} without writing $RUNVERIC_RESULT_FILE is a FAILED run, whatever the script printed.
|
|
7897
8938
|
Write it as the last thing your script does, on every path \u2014 including the ones that fail.`);
|
|
7898
8939
|
return 1;
|
|
7899
8940
|
}
|
|
@@ -7901,7 +8942,7 @@ async function reportOutcome(options) {
|
|
|
7901
8942
|
try {
|
|
7902
8943
|
parsed = JSON.parse(await readFile2(options.resultPath, "utf8"));
|
|
7903
8944
|
} catch {
|
|
7904
|
-
printError(style.red("\nresult.json is not valid JSON.") + ` ${
|
|
8945
|
+
printError(style.red("\nresult.json is not valid JSON.") + ` ${import_contracts8.BRAND_SHORT_NAME} refuses the run rather than guessing what the package meant.`);
|
|
7905
8946
|
return 1;
|
|
7906
8947
|
}
|
|
7907
8948
|
let result;
|
|
@@ -7909,14 +8950,14 @@ async function reportOutcome(options) {
|
|
|
7909
8950
|
result = (0, import_action_manifest4.validatePackageResult)(parsed, options.phase);
|
|
7910
8951
|
} catch (error) {
|
|
7911
8952
|
printError(style.red(`
|
|
7912
|
-
${
|
|
8953
|
+
${import_contracts8.BRAND_SHORT_NAME} would REFUSE this result.`) + `
|
|
7913
8954
|
${error instanceof Error ? error.message : String(error)}
|
|
7914
8955
|
This is the same check the control plane runs, so fixing it here fixes it there.`);
|
|
7915
8956
|
return 1;
|
|
7916
8957
|
}
|
|
7917
8958
|
printResult(result);
|
|
7918
8959
|
if (options.exit.code !== 0) {
|
|
7919
|
-
print(style.yellow(`The package exited ${options.exit.code} but wrote a valid result. ${
|
|
8960
|
+
print(style.yellow(`The package exited ${options.exit.code} but wrote a valid result. ${import_contracts8.BRAND_SHORT_NAME} reads the result, not the exit code \u2014 but a non-zero exit usually means something failed after the result was written.`));
|
|
7920
8961
|
print();
|
|
7921
8962
|
}
|
|
7922
8963
|
return result.status === "succeeded" ? 0 : 1;
|
|
@@ -7925,7 +8966,7 @@ __name(reportOutcome, "reportOutcome");
|
|
|
7925
8966
|
async function readJsonFile(path) {
|
|
7926
8967
|
let source;
|
|
7927
8968
|
try {
|
|
7928
|
-
source = await readFile2(
|
|
8969
|
+
source = await readFile2(resolve5(path), "utf8");
|
|
7929
8970
|
} catch {
|
|
7930
8971
|
throw new Error(`Could not read ${path}.`);
|
|
7931
8972
|
}
|
|
@@ -7943,9 +8984,9 @@ async function readJsonFile(path) {
|
|
|
7943
8984
|
__name(readJsonFile, "readJsonFile");
|
|
7944
8985
|
|
|
7945
8986
|
// src/main.ts
|
|
7946
|
-
var
|
|
8987
|
+
var import_contracts9 = __toESM(require_dist());
|
|
7947
8988
|
var USAGE = `
|
|
7948
|
-
${style.bold("runveric")} \u2014 author ${
|
|
8989
|
+
${style.bold("runveric")} \u2014 author ${import_contracts9.BRAND_ARTICLE} ${import_contracts9.BRAND_SHORT_NAME} action, without pushing anything.
|
|
7949
8990
|
|
|
7950
8991
|
${style.bold("USAGE")}
|
|
7951
8992
|
runveric <command> [options]
|
|
@@ -7953,8 +8994,9 @@ ${style.bold("USAGE")}
|
|
|
7953
8994
|
${style.bold("COMMANDS")}
|
|
7954
8995
|
init [directory] Scaffold a working action. It passes check and test immediately.
|
|
7955
8996
|
check Validate the package. Offline \u2014 no account, no cloud, no network.
|
|
7956
|
-
test Run one phase in the real ${
|
|
7957
|
-
publish Upload it to ${
|
|
8997
|
+
test Run one phase in the real ${import_contracts9.BRAND_SHORT_NAME} runner image.
|
|
8998
|
+
publish Upload it to ${import_contracts9.BRAND_SHORT_NAME} as an authored version. Needs an account.
|
|
8999
|
+
catalog <command> Publish first-party catalog artifacts. Not for authoring: see \`runveric catalog --help\`.
|
|
7958
9000
|
|
|
7959
9001
|
${style.bold("init")}
|
|
7960
9002
|
--id <publisher/name> The action id. Required.
|
|
@@ -7977,9 +9019,9 @@ ${style.bold("test")}
|
|
|
7977
9019
|
--keep Keep the materialized /runveric tree for inspection.
|
|
7978
9020
|
|
|
7979
9021
|
${style.bold("publish")}
|
|
7980
|
-
--to <url> Your ${
|
|
9022
|
+
--to <url> Your ${import_contracts9.BRAND_SHORT_NAME} URL. Defaults to $${URL_ENV}.
|
|
7981
9023
|
--token <token> Access token. Defaults to $${TOKEN_ENV}.
|
|
7982
|
-
--force Publish despite lint errors. Never bypasses ${
|
|
9024
|
+
--force Publish despite lint errors. Never bypasses ${import_contracts9.BRAND_SHORT_NAME}'s validation.
|
|
7983
9025
|
|
|
7984
9026
|
${style.bold("EVERYWHERE")}
|
|
7985
9027
|
--dir <path> The package directory. Defaults to the current directory.
|
|
@@ -8022,7 +9064,9 @@ __name(parseArgv, "parseArgv");
|
|
|
8022
9064
|
var first = /* @__PURE__ */ __name((parsed, name) => parsed.flags.get(name)?.[0], "first");
|
|
8023
9065
|
var bool = /* @__PURE__ */ __name((parsed, name) => parsed.flags.get(name)?.[0] === "true", "bool");
|
|
8024
9066
|
async function main() {
|
|
8025
|
-
const
|
|
9067
|
+
const argv = process.argv.slice(2);
|
|
9068
|
+
if (argv[0] === "catalog") return runCatalog(argv.slice(1));
|
|
9069
|
+
const parsed = parseArgv(argv);
|
|
8026
9070
|
if (parsed.flags.has("version")) {
|
|
8027
9071
|
print(version);
|
|
8028
9072
|
return 0;
|
|
@@ -8090,7 +9134,7 @@ async function main() {
|
|
|
8090
9134
|
force: bool(parsed, "force")
|
|
8091
9135
|
});
|
|
8092
9136
|
default:
|
|
8093
|
-
printError(style.red(`"${parsed.command}" is not a command.`) + " There are four: init, check, test, publish.");
|
|
9137
|
+
printError(style.red(`"${parsed.command}" is not a command.`) + " There are four: init, check, test, publish \u2014 and catalog, which publishes first-party catalog artifacts.");
|
|
8094
9138
|
return 1;
|
|
8095
9139
|
}
|
|
8096
9140
|
}
|