@theholocron/holocron-plugin-github 5.0.0-alpha.19 → 5.0.0-alpha.191

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/dist/index.d.mts CHANGED
@@ -1,11 +1,12 @@
1
1
  import { GitHubClient, GitHubClientOptions, createGitHubClient } from "@theholocron/github-client";
2
- import { Auth, AuthError, Ci, CiRun, CiRunFilter, Environment, Environments, Issue, IssueSearchFilter, Issues, LabelDef, LifecycleResult, LifecycleSlot, PagesConfig, PullRequest, RepoRef, RepoSettings, ResolveTokenInput, Ruleset, SecretScope, Secrets, Source, TeamEntry, TeamEntry as TeamEntry$1, TeamPermission, TrackerDoctorReport, TrackerUser, createFeatureResolver } from "@theholocron/cli";
2
+ import { Auth, AuthError, Ci, CiRun, CiRunFilter, Environment, Environments, Issue, IssueSearchFilter, Issues, LabelDef, LifecycleResult, LifecycleSlot, PagesConfig, PullRequest, RepoRef, RepoSettings, ResolveTokenInput, Ruleset, SecretScope, Secrets, Source, TeamEntry, TeamEntry as TeamEntry$1, TeamPermission, TrackerDoctorReport, TrackerUser, VerifyTokenFailure, VerifyTokenResult, VerifyTokenResult as VerifyTokenResult$1, VerifyTokenSuccess, createFeatureResolver } from "@theholocron/cli";
3
3
  //#region src/auth.d.ts
4
4
  declare const resolveReadToken: (input?: ResolveTokenInput) => string;
5
5
  declare const resolveIssuesToken: (input?: ResolveTokenInput) => string;
6
6
  declare const resolveSyncToken: (input?: ResolveTokenInput) => string;
7
7
  declare const resolveReleaseToken: (input?: ResolveTokenInput) => string;
8
8
  declare const resolveAdminToken: (input?: ResolveTokenInput) => string;
9
+ declare const resolveSecretsToken: (input?: ResolveTokenInput) => string;
9
10
  declare const resolveDeployToken: (input?: ResolveTokenInput) => string;
10
11
  declare const resolveOrgToken: (input?: ResolveTokenInput) => string;
11
12
  //#endregion
@@ -106,9 +107,16 @@ interface SecretsOptions {
106
107
  declare class GitHubSecrets implements Secrets {
107
108
  private readonly client;
108
109
  private readonly opts;
110
+ private readonly orgClient?;
109
111
  readonly key: "secrets";
110
112
  readonly providerName = "github";
111
- constructor(client: GitHubClient, opts: SecretsOptions);
113
+ /**
114
+ * `client` handles repo and environment scopes; `orgClient`, when given, handles
115
+ * the organization scope. They differ when a dedicated org-only token exists:
116
+ * it can write org secrets but not repo ones, and `github.admin` is the reverse.
117
+ */
118
+ constructor(client: GitHubClient, opts: SecretsOptions, orgClient?: GitHubClient | undefined);
119
+ private clientFor;
112
120
  listSecrets(scope: SecretScope): Promise<string[]>;
113
121
  setSecret(scope: SecretScope, name: string, value: string): Promise<void>;
114
122
  deleteSecret(scope: SecretScope, name: string): Promise<void>;
@@ -184,30 +192,11 @@ declare function syncTeams(client: GitHubClient, repo: string, teams: TeamEntry[
184
192
  declare function encryptSecret(publicKeyBase64: string, value: string): Promise<string>;
185
193
  //#endregion
186
194
  //#region src/verify-token.d.ts
187
- /**
188
- * `verifyToken` — plugin-level export used by `holocron auth set` +
189
- * `holocron auth check`. Hits `GET /user` and translates the response
190
- * into the normalized `VerifyTokenResult` shape.
191
- *
192
- * Kept as a standalone function (not a capability method) so the auth
193
- * command can call it without initializing the full plugin — plugin
194
- * construction requires an already-resolved token, which is exactly
195
- * what we don't have yet at bootstrap time.
196
- */
197
- interface VerifyTokenSuccess {
198
- ok: true;
199
- subject: string;
200
- }
201
- interface VerifyTokenFailure {
202
- ok: false;
203
- message: string;
204
- }
205
- type VerifyTokenResult = VerifyTokenSuccess | VerifyTokenFailure;
206
195
  interface VerifyTokenOptions {
207
196
  baseUrl?: string;
208
197
  fetch?: typeof fetch;
209
198
  }
210
- declare function verifyToken(token: string, opts?: VerifyTokenOptions): Promise<VerifyTokenResult>;
199
+ declare function verifyToken(token: string, opts?: VerifyTokenOptions): Promise<VerifyTokenResult$1>;
211
200
  //#endregion
212
201
  //#region src/index.d.ts
213
202
  interface GitHubPluginOptions extends ResolveTokenInput {
@@ -233,7 +222,7 @@ interface PluginContext {
233
222
  repoRoot: string;
234
223
  }
235
224
  declare function source(ctx: PluginContext, orgClient?: GitHubClient): Source;
236
- declare function secrets(ctx: PluginContext): Secrets;
225
+ declare function secrets(ctx: PluginContext, orgClient?: GitHubClient): Secrets;
237
226
  declare function environments(ctx: PluginContext): Environments;
238
227
  declare function ci(ctx: PluginContext): Ci;
239
228
  declare function issues(ctx: PluginContext): Issues;
@@ -253,4 +242,4 @@ declare function createPlugin(options: GitHubPluginOptions): {
253
242
  */
254
243
  declare const AUTH_HINT: string;
255
244
  //#endregion
256
- export { AUTH_HINT, type Auth, AuthError, type CanonicalLabel, GitHubCi, type GitHubClientOptions, GitHubEnvironments, GitHubIssues, GitHubPluginOptions, GitHubSecrets, GitHubSource, type NormalizedTeamEntry, PluginContext, type ResolveTokenInput, type TeamEntry, type TeamPermission, type VerifyTokenFailure, type VerifyTokenResult, type VerifyTokenSuccess, ci, createFeatureResolver, createGitHubClient, createPlugin, encryptSecret, environments, issues, normalizeTeamEntry, resolveAdminToken, resolveDeployToken, resolveIssuesToken, resolveOrgToken, resolveReadToken, resolveReleaseToken, resolveSyncToken, secrets, source, syncLabels, syncTeams, verifyToken };
245
+ export { AUTH_HINT, type Auth, AuthError, type CanonicalLabel, GitHubCi, type GitHubClientOptions, GitHubEnvironments, GitHubIssues, GitHubPluginOptions, GitHubSecrets, GitHubSource, type NormalizedTeamEntry, PluginContext, type ResolveTokenInput, type TeamEntry, type TeamPermission, type VerifyTokenFailure, type VerifyTokenResult, type VerifyTokenSuccess, ci, createFeatureResolver, createGitHubClient, createPlugin, encryptSecret, environments, issues, normalizeTeamEntry, resolveAdminToken, resolveDeployToken, resolveIssuesToken, resolveOrgToken, resolveReadToken, resolveReleaseToken, resolveSecretsToken, resolveSyncToken, secrets, source, syncLabels, syncTeams, verifyToken };
package/dist/index.mjs CHANGED
@@ -3,6 +3,8 @@ import { createGitHubClient, createGitHubClient as createGitHubClient$1 } from "
3
3
  import { AuthError, createFeatureResolver } from "@theholocron/cli";
4
4
  import { mkdir, readFile, readdir, rm, stat, writeFile } from "node:fs/promises";
5
5
  import { dirname, join } from "node:path";
6
+ import { findRootSync } from "@theholocron/fs-utils";
7
+ import { errorMessage } from "@theholocron/misc-utils";
6
8
  //#region src/auth.ts
7
9
  const resolveReadToken = createFeatureResolver({
8
10
  envName: "HOLOCRON_READ_TOKEN",
@@ -24,6 +26,10 @@ const resolveAdminToken = createFeatureResolver({
24
26
  envName: "HOLOCRON_ADMIN_TOKEN",
25
27
  keyringKey: "github.admin"
26
28
  });
29
+ const resolveSecretsToken = createFeatureResolver({
30
+ envName: "HOLOCRON_SECRETS_TOKEN",
31
+ keyringKey: "github.secrets"
32
+ });
27
33
  const resolveDeployToken = createFeatureResolver({
28
34
  envName: "HOLOCRON_DEPLOY_TOKEN",
29
35
  keyringKey: "github.deploy"
@@ -374,27 +380,38 @@ async function encryptSecret(publicKeyBase64, value) {
374
380
  var GitHubSecrets = class {
375
381
  client;
376
382
  opts;
383
+ orgClient;
377
384
  key = "secrets";
378
385
  providerName = "github";
379
- constructor(client, opts) {
386
+ /**
387
+ * `client` handles repo and environment scopes; `orgClient`, when given, handles
388
+ * the organization scope. They differ when a dedicated org-only token exists:
389
+ * it can write org secrets but not repo ones, and `github.admin` is the reverse.
390
+ */
391
+ constructor(client, opts, orgClient) {
380
392
  this.client = client;
381
393
  this.opts = opts;
394
+ this.orgClient = orgClient;
395
+ }
396
+ clientFor(scope) {
397
+ return scope.kind === "organization" ? this.orgClient ?? this.client : this.client;
382
398
  }
383
399
  async listSecrets(scope) {
384
- return this.client.secrets.listSecrets(this.opts.repo, toGHScope(scope));
400
+ return this.clientFor(scope).secrets.listSecrets(this.opts.repo, toGHScope(scope));
385
401
  }
386
402
  async setSecret(scope, name, value) {
387
403
  const ghScope = toGHScope(scope);
388
- const pk = await this.client.secrets.getPublicKey(this.opts.repo, ghScope);
404
+ const client = this.clientFor(scope);
405
+ const pk = await client.secrets.getPublicKey(this.opts.repo, ghScope);
389
406
  const body = {
390
407
  encrypted_value: await encryptSecret(pk.key, value),
391
408
  key_id: pk.key_id
392
409
  };
393
410
  if (scope.kind === "organization") body.visibility = "all";
394
- await this.client.secrets.putSecret(this.opts.repo, ghScope, name, body);
411
+ await client.secrets.putSecret(this.opts.repo, ghScope, name, body);
395
412
  }
396
413
  async deleteSecret(scope, name) {
397
- await this.client.secrets.deleteSecret(this.opts.repo, toGHScope(scope), name);
414
+ await this.clientFor(scope).secrets.deleteSecret(this.opts.repo, toGHScope(scope), name);
398
415
  }
399
416
  };
400
417
  function toGHScope(scope) {
@@ -496,8 +513,11 @@ var GitHubSource = class {
496
513
  this.owner = owner;
497
514
  this.name = name;
498
515
  this.repo = opts.repo;
499
- this.repoRoot = opts.repoRoot;
500
- this.workflowDir = join(opts.repoRoot, ".github", "workflows");
516
+ this.repoRoot = findRootSync(opts.repoRoot, ".git", {
517
+ fallback: "start",
518
+ realpath: true
519
+ });
520
+ this.workflowDir = join(this.repoRoot, ".github", "workflows");
501
521
  this.orgClient = opts.orgClient;
502
522
  this.baseUrl = opts.baseUrl;
503
523
  this.fetchImpl = opts.fetch;
@@ -652,16 +672,6 @@ async function ensureDir(path) {
652
672
  }
653
673
  //#endregion
654
674
  //#region src/verify-token.ts
655
- /**
656
- * `verifyToken` — plugin-level export used by `holocron auth set` +
657
- * `holocron auth check`. Hits `GET /user` and translates the response
658
- * into the normalized `VerifyTokenResult` shape.
659
- *
660
- * Kept as a standalone function (not a capability method) so the auth
661
- * command can call it without initializing the full plugin — plugin
662
- * construction requires an already-resolved token, which is exactly
663
- * what we don't have yet at bootstrap time.
664
- */
665
675
  async function verifyToken(token, opts = {}) {
666
676
  const client = createGitHubClient({
667
677
  token,
@@ -677,7 +687,7 @@ async function verifyToken(token, opts = {}) {
677
687
  } catch (err) {
678
688
  return {
679
689
  ok: false,
680
- message: err instanceof Error ? err.message : String(err)
690
+ message: errorMessage(err)
681
691
  };
682
692
  }
683
693
  }
@@ -692,8 +702,8 @@ function source(ctx, orgClient) {
692
702
  fetch: ctx.options.fetch
693
703
  });
694
704
  }
695
- function secrets(ctx) {
696
- return new GitHubSecrets(ctx.client, { repo: ctx.repo });
705
+ function secrets(ctx, orgClient) {
706
+ return new GitHubSecrets(ctx.client, { repo: ctx.repo }, orgClient);
697
707
  }
698
708
  function environments(ctx) {
699
709
  return new GitHubEnvironments(ctx.client, { repo: ctx.repo });
@@ -708,10 +718,11 @@ function issues(ctx) {
708
718
  }
709
719
  function createPlugin(options) {
710
720
  function makeCtx(resolver) {
721
+ const token = resolver(options);
711
722
  return {
712
723
  options,
713
724
  client: createGitHubClient$1({
714
- token: resolver(options),
725
+ token,
715
726
  baseUrl: options.baseUrl,
716
727
  fetch: options.fetch
717
728
  }),
@@ -719,10 +730,45 @@ function createPlugin(options) {
719
730
  repoRoot: options.repoRoot ?? process.cwd()
720
731
  };
721
732
  }
733
+ /** A token, or undefined when that feature token is simply not configured. */
734
+ function tryResolve(resolver) {
735
+ try {
736
+ return resolver(options);
737
+ } catch (err) {
738
+ if (err instanceof AuthError) return void 0;
739
+ throw err;
740
+ }
741
+ }
742
+ /**
743
+ * Organization secrets need an org-resource-owner token (`github.secrets`);
744
+ * repo and environment secrets need `github.admin`. Each scope prefers its own
745
+ * token and falls back to the other, so a setup with only one of them keeps
746
+ * working, and an explicit `--token` serves both. With neither configured this
747
+ * fails exactly as the admin-token capabilities do.
748
+ */
749
+ function makeSecrets() {
750
+ const secretsToken = tryResolve(resolveSecretsToken);
751
+ const adminToken = tryResolve(resolveAdminToken);
752
+ if (!secretsToken && !adminToken) resolveAdminToken(options);
753
+ const clientFor = (token) => createGitHubClient$1({
754
+ token,
755
+ baseUrl: options.baseUrl,
756
+ fetch: options.fetch
757
+ });
758
+ const repoClient = clientFor(adminToken ?? secretsToken);
759
+ const orgClient = clientFor(secretsToken ?? adminToken);
760
+ return secrets({
761
+ options,
762
+ client: repoClient,
763
+ repo: options.repo,
764
+ repoRoot: options.repoRoot ?? process.cwd()
765
+ }, orgClient);
766
+ }
722
767
  function makeOrgClient() {
723
768
  try {
769
+ const token = resolveOrgToken(options);
724
770
  return createGitHubClient$1({
725
- token: resolveOrgToken(options),
771
+ token,
726
772
  baseUrl: options.baseUrl,
727
773
  fetch: options.fetch
728
774
  });
@@ -735,7 +781,7 @@ function createPlugin(options) {
735
781
  capabilities: {
736
782
  source: () => source(makeCtx(resolveAdminToken), makeOrgClient()),
737
783
  ci: () => ci(makeCtx(resolveReadToken)),
738
- secrets: () => secrets(makeCtx(resolveAdminToken)),
784
+ secrets: () => makeSecrets(),
739
785
  environments: () => environments(makeCtx(resolveAdminToken)),
740
786
  issues: () => issues(makeCtx(resolveIssuesToken))
741
787
  }
@@ -747,4 +793,4 @@ function createPlugin(options) {
747
793
  */
748
794
  const AUTH_HINT = "generate fine-grained Personal Access Tokens at https://github.com/settings/tokens (one per feature — see docs/tokens.md for required scopes per operation), then run: holocron auth set github.<feature> <PAT>";
749
795
  //#endregion
750
- export { AUTH_HINT, AuthError, GitHubCi, GitHubEnvironments, GitHubIssues, GitHubSecrets, GitHubSource, ci, createFeatureResolver, createGitHubClient, createPlugin, encryptSecret, environments, issues, normalizeTeamEntry, resolveAdminToken, resolveDeployToken, resolveIssuesToken, resolveOrgToken, resolveReadToken, resolveReleaseToken, resolveSyncToken, secrets, source, syncLabels, syncTeams, verifyToken };
796
+ export { AUTH_HINT, AuthError, GitHubCi, GitHubEnvironments, GitHubIssues, GitHubSecrets, GitHubSource, ci, createFeatureResolver, createGitHubClient, createPlugin, encryptSecret, environments, issues, normalizeTeamEntry, resolveAdminToken, resolveDeployToken, resolveIssuesToken, resolveOrgToken, resolveReadToken, resolveReleaseToken, resolveSecretsToken, resolveSyncToken, secrets, source, syncLabels, syncTeams, verifyToken };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@theholocron/holocron-plugin-github",
3
- "version": "5.0.0-alpha.19",
3
+ "version": "5.0.0-alpha.191",
4
4
  "description": "Holocron plugin for GitHub. Implements source, ci, secrets, environments, and issues capabilities against the GitHub REST API.",
5
5
  "keywords": [
6
6
  "ci",
@@ -9,12 +9,12 @@
9
9
  "plugin",
10
10
  "source"
11
11
  ],
12
- "homepage": "https://github.com/theholocron/holocron/tree/main/packages/holocron-plugin-github#readme",
12
+ "homepage": "https://github.com/theholocron/holocron/tree/main/plugins/holocron-plugin-github#readme",
13
13
  "bugs": "https://github.com/theholocron/holocron/issues",
14
14
  "repository": {
15
15
  "type": "git",
16
16
  "url": "git+https://github.com/theholocron/holocron.git",
17
- "directory": "packages/holocron-plugin-github"
17
+ "directory": "plugins/holocron-plugin-github"
18
18
  },
19
19
  "license": "MIT",
20
20
  "author": "Newton Koumantzelis",
@@ -34,12 +34,14 @@
34
34
  "libsodium-wrappers": "^0.8.4"
35
35
  },
36
36
  "devDependencies": {
37
- "@theholocron/eslint-config": "^8.0.0",
38
- "@theholocron/github-client": "^1.19.0",
39
- "@theholocron/http-client": "^1.19.0",
40
- "@theholocron/tsconfig": "^8.0.0",
41
- "@theholocron/tsdown-config": "^8.0.0",
42
- "@theholocron/vitest-config": "^8.0.0",
37
+ "@theholocron/eslint-config": "^8.8.2",
38
+ "@theholocron/fs-utils": "^1.16.0",
39
+ "@theholocron/github-client": "^1.43.1",
40
+ "@theholocron/http-client": "^1.43.1",
41
+ "@theholocron/misc-utils": "^1.16.0",
42
+ "@theholocron/tsconfig": "^8.8.2",
43
+ "@theholocron/tsdown-config": "^8.8.2",
44
+ "@theholocron/vitest-config": "^8.8.2",
43
45
  "@types/node": "^26",
44
46
  "@vitest/coverage-v8": "^4.1.11",
45
47
  "@vitest/eslint-plugin": "^1.6.27",
@@ -47,14 +49,16 @@
47
49
  "eslint-plugin-n": "^18.3.0",
48
50
  "globals": "^17.11.0",
49
51
  "tsdown": "^0.22.14",
50
- "tsx": "4.23.12",
52
+ "tsx": "4.23.15",
51
53
  "typescript": "^5.9.3",
52
54
  "vitest": "^4.1.11",
53
- "@theholocron/cli": "5.0.0-alpha.19"
55
+ "@theholocron/cli": "5.0.0-alpha.191"
54
56
  },
55
57
  "peerDependencies": {
56
- "@theholocron/github-client": "^1.19.0",
57
- "@theholocron/cli": "5.0.0-alpha.19"
58
+ "@theholocron/fs-utils": "^1.16.0",
59
+ "@theholocron/github-client": "^1.43.1",
60
+ "@theholocron/misc-utils": "^1.16.0",
61
+ "@theholocron/cli": "5.0.0-alpha.191"
58
62
  },
59
63
  "engines": {
60
64
  "node": ">=22"