paperclip-github-plugin 0.9.0 → 0.9.2
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 +11 -2
- package/dist/manifest.js +1 -1
- package/dist/ui/index.js +133 -8
- package/dist/ui/index.js.map +2 -2
- package/dist/worker.js +264 -6
- package/package.json +1 -1
package/dist/worker.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
// src/worker.ts
|
|
2
2
|
import { Buffer } from "node:buffer";
|
|
3
3
|
import { realpathSync } from "node:fs";
|
|
4
|
-
import { readFile } from "node:fs/promises";
|
|
4
|
+
import { chmod, mkdir, readFile, writeFile } from "node:fs/promises";
|
|
5
5
|
import { homedir } from "node:os";
|
|
6
|
-
import { join, resolve } from "node:path";
|
|
6
|
+
import { dirname, join, resolve } from "node:path";
|
|
7
7
|
import { fileURLToPath } from "node:url";
|
|
8
8
|
import { Octokit } from "@octokit/rest";
|
|
9
9
|
import {
|
|
@@ -1604,6 +1604,10 @@ function getErrorMessage(error) {
|
|
|
1604
1604
|
}
|
|
1605
1605
|
return String(error);
|
|
1606
1606
|
}
|
|
1607
|
+
function isPluginSecretReferenceDisabledError(error) {
|
|
1608
|
+
const message = getErrorMessage(error).toLowerCase();
|
|
1609
|
+
return message.includes("plugin secret reference") && message.includes("disabled") || message.includes("company-scoped plugin config lands");
|
|
1610
|
+
}
|
|
1607
1611
|
function getErrorCause(error) {
|
|
1608
1612
|
if (!error || typeof error !== "object" || !("cause" in error)) {
|
|
1609
1613
|
return void 0;
|
|
@@ -1974,6 +1978,34 @@ function normalizeGitHubTokenRefs(value) {
|
|
|
1974
1978
|
}
|
|
1975
1979
|
return Object.fromEntries(entries);
|
|
1976
1980
|
}
|
|
1981
|
+
function normalizeGitHubTokensByCompanyId(value) {
|
|
1982
|
+
if (!value || typeof value !== "object") {
|
|
1983
|
+
return void 0;
|
|
1984
|
+
}
|
|
1985
|
+
const entries = Object.entries(value).map(([companyId, token]) => {
|
|
1986
|
+
const normalizedCompanyId = normalizeCompanyId(companyId);
|
|
1987
|
+
const normalizedToken = normalizeGitHubToken(token);
|
|
1988
|
+
return normalizedCompanyId && normalizedToken ? [normalizedCompanyId, normalizedToken] : null;
|
|
1989
|
+
}).filter((entry) => entry !== null);
|
|
1990
|
+
if (entries.length === 0) {
|
|
1991
|
+
return void 0;
|
|
1992
|
+
}
|
|
1993
|
+
return Object.fromEntries(entries);
|
|
1994
|
+
}
|
|
1995
|
+
function normalizePaperclipBoardApiTokensByCompanyId(value) {
|
|
1996
|
+
if (!value || typeof value !== "object") {
|
|
1997
|
+
return void 0;
|
|
1998
|
+
}
|
|
1999
|
+
const entries = Object.entries(value).map(([companyId, token]) => {
|
|
2000
|
+
const normalizedCompanyId = normalizeCompanyId(companyId);
|
|
2001
|
+
const normalizedToken = normalizeGitHubToken(token);
|
|
2002
|
+
return normalizedCompanyId && normalizedToken ? [normalizedCompanyId, normalizedToken] : null;
|
|
2003
|
+
}).filter((entry) => entry !== null);
|
|
2004
|
+
if (entries.length === 0) {
|
|
2005
|
+
return void 0;
|
|
2006
|
+
}
|
|
2007
|
+
return Object.fromEntries(entries);
|
|
2008
|
+
}
|
|
1977
2009
|
function formatUtcTimestamp(value) {
|
|
1978
2010
|
const parsed = new Date(value);
|
|
1979
2011
|
if (Number.isNaN(parsed.getTime())) {
|
|
@@ -3710,13 +3742,17 @@ function normalizeConfig(value) {
|
|
|
3710
3742
|
const githubTokenRefs = normalizeGitHubTokenRefs(record.githubTokenRefs);
|
|
3711
3743
|
const githubTokenRef = normalizeGitHubTokenRef(record.githubTokenRef);
|
|
3712
3744
|
const githubToken = normalizeGitHubToken(record.githubToken);
|
|
3745
|
+
const githubTokensByCompanyId = normalizeGitHubTokensByCompanyId(record.githubTokensByCompanyId);
|
|
3713
3746
|
const paperclipBoardApiTokenRefs = normalizePaperclipBoardApiTokenRefs(record.paperclipBoardApiTokenRefs);
|
|
3747
|
+
const paperclipBoardApiTokensByCompanyId = normalizePaperclipBoardApiTokensByCompanyId(record.paperclipBoardApiTokensByCompanyId);
|
|
3714
3748
|
const paperclipApiBaseUrl = normalizePaperclipApiBaseUrl(record.paperclipApiBaseUrl);
|
|
3715
3749
|
return {
|
|
3716
3750
|
...githubTokenRefs ? { githubTokenRefs } : {},
|
|
3717
3751
|
...githubTokenRef ? { githubTokenRef } : {},
|
|
3718
3752
|
...githubToken ? { githubToken } : {},
|
|
3753
|
+
...githubTokensByCompanyId ? { githubTokensByCompanyId } : {},
|
|
3719
3754
|
...paperclipBoardApiTokenRefs ? { paperclipBoardApiTokenRefs } : {},
|
|
3755
|
+
...paperclipBoardApiTokensByCompanyId ? { paperclipBoardApiTokensByCompanyId } : {},
|
|
3720
3756
|
...paperclipApiBaseUrl ? { paperclipApiBaseUrl } : {}
|
|
3721
3757
|
};
|
|
3722
3758
|
}
|
|
@@ -3791,6 +3827,129 @@ async function readExternalConfig(ctx) {
|
|
|
3791
3827
|
return {};
|
|
3792
3828
|
}
|
|
3793
3829
|
}
|
|
3830
|
+
async function readExternalConfigRecordForWrite(ctx, filePath) {
|
|
3831
|
+
try {
|
|
3832
|
+
const rawConfig = await readFile(filePath, "utf8");
|
|
3833
|
+
const parsedConfig = JSON.parse(rawConfig);
|
|
3834
|
+
return parsedConfig && typeof parsedConfig === "object" && !Array.isArray(parsedConfig) ? { ...parsedConfig } : {};
|
|
3835
|
+
} catch (error) {
|
|
3836
|
+
const errorCode = error && typeof error === "object" && "code" in error ? error.code : void 0;
|
|
3837
|
+
if (errorCode === "ENOENT") {
|
|
3838
|
+
return {};
|
|
3839
|
+
}
|
|
3840
|
+
if (error instanceof SyntaxError) {
|
|
3841
|
+
ctx.logger.warn("Ignoring the GitHub Sync worker-local token fallback config file because it is not valid JSON.", {
|
|
3842
|
+
filePath,
|
|
3843
|
+
error: error.message
|
|
3844
|
+
});
|
|
3845
|
+
return {};
|
|
3846
|
+
}
|
|
3847
|
+
throw error;
|
|
3848
|
+
}
|
|
3849
|
+
}
|
|
3850
|
+
async function writeExternalCompanyGitHubTokenFallback(ctx, companyId, token) {
|
|
3851
|
+
const externalConfigFilePath = getExternalConfigFilePath();
|
|
3852
|
+
if (!externalConfigFilePath) {
|
|
3853
|
+
throw new Error("Could not resolve a Paperclip home directory for the GitHub Sync fallback token config.");
|
|
3854
|
+
}
|
|
3855
|
+
const currentRecord = await readExternalConfigRecordForWrite(ctx, externalConfigFilePath);
|
|
3856
|
+
const currentCompanyTokens = normalizeGitHubTokensByCompanyId(currentRecord.githubTokensByCompanyId) ?? {};
|
|
3857
|
+
const nextRecord = {
|
|
3858
|
+
...currentRecord,
|
|
3859
|
+
githubTokensByCompanyId: {
|
|
3860
|
+
...currentCompanyTokens,
|
|
3861
|
+
[companyId]: token
|
|
3862
|
+
}
|
|
3863
|
+
};
|
|
3864
|
+
await mkdir(dirname(externalConfigFilePath), { recursive: true });
|
|
3865
|
+
await writeFile(externalConfigFilePath, `${JSON.stringify(nextRecord, null, 2)}
|
|
3866
|
+
`, {
|
|
3867
|
+
encoding: "utf8",
|
|
3868
|
+
mode: 384
|
|
3869
|
+
});
|
|
3870
|
+
try {
|
|
3871
|
+
await chmod(externalConfigFilePath, 384);
|
|
3872
|
+
} catch (error) {
|
|
3873
|
+
ctx.logger.warn("GitHub Sync could not tighten permissions on the worker-local token fallback file.", {
|
|
3874
|
+
filePath: externalConfigFilePath,
|
|
3875
|
+
error: getErrorMessage(error)
|
|
3876
|
+
});
|
|
3877
|
+
}
|
|
3878
|
+
}
|
|
3879
|
+
async function writeExternalCompanyPaperclipBoardApiTokenFallback(ctx, companyId, token) {
|
|
3880
|
+
const externalConfigFilePath = getExternalConfigFilePath();
|
|
3881
|
+
if (!externalConfigFilePath) {
|
|
3882
|
+
throw new Error("Could not resolve a Paperclip home directory for the GitHub Sync fallback token config.");
|
|
3883
|
+
}
|
|
3884
|
+
const currentRecord = await readExternalConfigRecordForWrite(ctx, externalConfigFilePath);
|
|
3885
|
+
const currentCompanyTokens = normalizePaperclipBoardApiTokensByCompanyId(currentRecord.paperclipBoardApiTokensByCompanyId) ?? {};
|
|
3886
|
+
const nextRecord = {
|
|
3887
|
+
...currentRecord,
|
|
3888
|
+
paperclipBoardApiTokensByCompanyId: {
|
|
3889
|
+
...currentCompanyTokens,
|
|
3890
|
+
[companyId]: token
|
|
3891
|
+
}
|
|
3892
|
+
};
|
|
3893
|
+
await mkdir(dirname(externalConfigFilePath), { recursive: true });
|
|
3894
|
+
await writeFile(externalConfigFilePath, `${JSON.stringify(nextRecord, null, 2)}
|
|
3895
|
+
`, {
|
|
3896
|
+
encoding: "utf8",
|
|
3897
|
+
mode: 384
|
|
3898
|
+
});
|
|
3899
|
+
try {
|
|
3900
|
+
await chmod(externalConfigFilePath, 384);
|
|
3901
|
+
} catch (error) {
|
|
3902
|
+
ctx.logger.warn("GitHub Sync could not tighten permissions on the worker-local token fallback file.", {
|
|
3903
|
+
filePath: externalConfigFilePath,
|
|
3904
|
+
error: getErrorMessage(error)
|
|
3905
|
+
});
|
|
3906
|
+
}
|
|
3907
|
+
}
|
|
3908
|
+
async function clearExternalCompanyPaperclipBoardApiTokenFallback(ctx, companyId) {
|
|
3909
|
+
const externalConfigFilePath = getExternalConfigFilePath();
|
|
3910
|
+
if (!externalConfigFilePath) {
|
|
3911
|
+
return;
|
|
3912
|
+
}
|
|
3913
|
+
const currentRecord = await readExternalConfigRecordForWrite(ctx, externalConfigFilePath);
|
|
3914
|
+
const currentCompanyTokens = normalizePaperclipBoardApiTokensByCompanyId(currentRecord.paperclipBoardApiTokensByCompanyId) ?? {};
|
|
3915
|
+
if (!(companyId in currentCompanyTokens)) {
|
|
3916
|
+
return;
|
|
3917
|
+
}
|
|
3918
|
+
const nextCompanyTokens = { ...currentCompanyTokens };
|
|
3919
|
+
delete nextCompanyTokens[companyId];
|
|
3920
|
+
const nextRecord = { ...currentRecord };
|
|
3921
|
+
if (Object.keys(nextCompanyTokens).length > 0) {
|
|
3922
|
+
nextRecord.paperclipBoardApiTokensByCompanyId = nextCompanyTokens;
|
|
3923
|
+
} else {
|
|
3924
|
+
delete nextRecord.paperclipBoardApiTokensByCompanyId;
|
|
3925
|
+
}
|
|
3926
|
+
await mkdir(dirname(externalConfigFilePath), { recursive: true });
|
|
3927
|
+
await writeFile(externalConfigFilePath, `${JSON.stringify(nextRecord, null, 2)}
|
|
3928
|
+
`, {
|
|
3929
|
+
encoding: "utf8",
|
|
3930
|
+
mode: 384
|
|
3931
|
+
});
|
|
3932
|
+
try {
|
|
3933
|
+
await chmod(externalConfigFilePath, 384);
|
|
3934
|
+
} catch (error) {
|
|
3935
|
+
ctx.logger.warn("GitHub Sync could not tighten permissions on the worker-local token fallback file.", {
|
|
3936
|
+
filePath: externalConfigFilePath,
|
|
3937
|
+
error: getErrorMessage(error)
|
|
3938
|
+
});
|
|
3939
|
+
}
|
|
3940
|
+
}
|
|
3941
|
+
async function shouldSeedExternalPaperclipBoardTokenFallback(ctx, companyId, secretRef) {
|
|
3942
|
+
try {
|
|
3943
|
+
return !(await ctx.secrets.resolve(secretRef)).trim();
|
|
3944
|
+
} catch (error) {
|
|
3945
|
+
ctx.logger.warn("Unable to resolve the saved Paperclip board API token while checking worker fallback necessity.", {
|
|
3946
|
+
companyId,
|
|
3947
|
+
secretRef,
|
|
3948
|
+
error: getErrorMessage(error)
|
|
3949
|
+
});
|
|
3950
|
+
return true;
|
|
3951
|
+
}
|
|
3952
|
+
}
|
|
3794
3953
|
function normalizePaperclipBoardApiTokenRefs(value) {
|
|
3795
3954
|
if (!value || typeof value !== "object") {
|
|
3796
3955
|
return void 0;
|
|
@@ -9985,6 +10144,7 @@ async function getResolvedConfig(ctx) {
|
|
|
9985
10144
|
}
|
|
9986
10145
|
function getConfiguredGithubTokenSource(settings, config, companyId) {
|
|
9987
10146
|
const normalizedCompanyId = normalizeCompanyId(companyId);
|
|
10147
|
+
const companyFallbackToken = normalizedCompanyId ? normalizeGitHubToken(config.githubTokensByCompanyId?.[normalizedCompanyId]) : void 0;
|
|
9988
10148
|
const hasScopedGitHubTokenRefs = hasAnyScopedValue(settings?.githubTokenRefs) || hasAnyScopedValue(config.githubTokenRefs);
|
|
9989
10149
|
const secretRef = normalizedCompanyId ? normalizeSecretRef(config.githubTokenRefs?.[normalizedCompanyId]) ?? normalizeSecretRef(settings?.githubTokenRefs?.[normalizedCompanyId]) ?? (!hasScopedGitHubTokenRefs ? normalizeGitHubTokenRef(config.githubTokenRef) ?? normalizeGitHubTokenRef(settings?.githubTokenRef) : void 0) : normalizeGitHubTokenRef(config.githubTokenRef) ?? normalizeGitHubTokenRef(settings?.githubTokenRef) ?? (() => {
|
|
9990
10150
|
const configuredRefs = [
|
|
@@ -9995,14 +10155,17 @@ function getConfiguredGithubTokenSource(settings, config, companyId) {
|
|
|
9995
10155
|
return uniqueRefs.length === 1 ? uniqueRefs[0] : void 0;
|
|
9996
10156
|
})();
|
|
9997
10157
|
if (secretRef) {
|
|
9998
|
-
return {
|
|
10158
|
+
return {
|
|
10159
|
+
secretRef,
|
|
10160
|
+
...companyFallbackToken ? { fallbackToken: companyFallbackToken } : {}
|
|
10161
|
+
};
|
|
9999
10162
|
}
|
|
10000
|
-
const token = !normalizedCompanyId || !hasScopedGitHubTokenRefs ? normalizeGitHubToken(config.githubToken) : void 0;
|
|
10163
|
+
const token = companyFallbackToken ?? (!normalizedCompanyId || !hasScopedGitHubTokenRefs ? normalizeGitHubToken(config.githubToken) : void 0);
|
|
10001
10164
|
return token ? { token } : {};
|
|
10002
10165
|
}
|
|
10003
10166
|
function hasConfiguredGithubToken(settings, config, companyId) {
|
|
10004
10167
|
const configuredTokenSource = getConfiguredGithubTokenSource(settings, config, companyId);
|
|
10005
|
-
if (configuredTokenSource.secretRef ?? configuredTokenSource.token) {
|
|
10168
|
+
if (configuredTokenSource.secretRef ?? configuredTokenSource.token ?? configuredTokenSource.fallbackToken) {
|
|
10006
10169
|
return true;
|
|
10007
10170
|
}
|
|
10008
10171
|
if (normalizeCompanyId(companyId)) {
|
|
@@ -10012,6 +10175,18 @@ function hasConfiguredGithubToken(settings, config, companyId) {
|
|
|
10012
10175
|
settings?.githubTokenRefs && Object.keys(settings.githubTokenRefs).length > 0 || config.githubTokenRefs && Object.keys(config.githubTokenRefs).length > 0
|
|
10013
10176
|
);
|
|
10014
10177
|
}
|
|
10178
|
+
function getSavedGitHubTokenRef(settings, companyId) {
|
|
10179
|
+
if (!companyId) {
|
|
10180
|
+
return void 0;
|
|
10181
|
+
}
|
|
10182
|
+
return normalizeSecretRef(settings?.githubTokenRefs?.[companyId]);
|
|
10183
|
+
}
|
|
10184
|
+
function getConfiguredGitHubTokenRef(config, companyId) {
|
|
10185
|
+
if (!companyId) {
|
|
10186
|
+
return void 0;
|
|
10187
|
+
}
|
|
10188
|
+
return normalizeSecretRef(config?.githubTokenRefs?.[companyId]);
|
|
10189
|
+
}
|
|
10015
10190
|
function getSavedPaperclipBoardApiTokenRef(settings, companyId) {
|
|
10016
10191
|
if (!companyId) {
|
|
10017
10192
|
return void 0;
|
|
@@ -10061,11 +10236,16 @@ async function resolvePaperclipApiAuthTokens(ctx, settings, config, mappings) {
|
|
|
10061
10236
|
for (const companyId of companyIds) {
|
|
10062
10237
|
const configuredSecretRef = getConfiguredPaperclipBoardApiTokenRef(config, companyId);
|
|
10063
10238
|
const savedSecretRef = getSavedPaperclipBoardApiTokenRef(settings, companyId);
|
|
10239
|
+
const fallbackToken = normalizeGitHubToken(config.paperclipBoardApiTokensByCompanyId?.[companyId]);
|
|
10064
10240
|
const secretRef = configuredSecretRef ?? savedSecretRef;
|
|
10065
10241
|
if (!secretRef) {
|
|
10066
10242
|
continue;
|
|
10067
10243
|
}
|
|
10068
10244
|
if (!configuredSecretRef && savedSecretRef) {
|
|
10245
|
+
if (fallbackToken) {
|
|
10246
|
+
tokensByCompanyId.set(companyId, fallbackToken);
|
|
10247
|
+
continue;
|
|
10248
|
+
}
|
|
10069
10249
|
ctx.logger.warn(
|
|
10070
10250
|
"Paperclip board access is saved in plugin state but has not been mirrored into plugin config yet. Open plugin settings to finish migrating it, or reconnect board access, before retrying sync.",
|
|
10071
10251
|
{
|
|
@@ -10081,6 +10261,15 @@ async function resolvePaperclipApiAuthTokens(ctx, settings, config, mappings) {
|
|
|
10081
10261
|
tokensByCompanyId.set(companyId, token);
|
|
10082
10262
|
}
|
|
10083
10263
|
} catch (error) {
|
|
10264
|
+
if (fallbackToken && isPluginSecretReferenceDisabledError(error)) {
|
|
10265
|
+
ctx.logger.warn("GitHub Sync is using a worker-local Paperclip board token fallback because plugin secret refs are unavailable in this host.", {
|
|
10266
|
+
companyId,
|
|
10267
|
+
secretRef,
|
|
10268
|
+
error: getErrorMessage(error)
|
|
10269
|
+
});
|
|
10270
|
+
tokensByCompanyId.set(companyId, fallbackToken);
|
|
10271
|
+
continue;
|
|
10272
|
+
}
|
|
10084
10273
|
ctx.logger.warn("Unable to resolve the saved Paperclip board API token. Direct REST calls will continue without it.", {
|
|
10085
10274
|
companyId,
|
|
10086
10275
|
secretRef,
|
|
@@ -10095,7 +10284,23 @@ async function resolveGithubToken(ctx, options = {}) {
|
|
|
10095
10284
|
const config = options.config ?? await getResolvedConfig(ctx);
|
|
10096
10285
|
const configuredTokenSource = getConfiguredGithubTokenSource(settings, config, options.companyId);
|
|
10097
10286
|
if (configuredTokenSource.secretRef) {
|
|
10098
|
-
|
|
10287
|
+
try {
|
|
10288
|
+
const token = (await ctx.secrets.resolve(configuredTokenSource.secretRef)).trim();
|
|
10289
|
+
if (token) {
|
|
10290
|
+
return token;
|
|
10291
|
+
}
|
|
10292
|
+
return configuredTokenSource.fallbackToken ?? "";
|
|
10293
|
+
} catch (error) {
|
|
10294
|
+
if (configuredTokenSource.fallbackToken && isPluginSecretReferenceDisabledError(error)) {
|
|
10295
|
+
ctx.logger.warn("GitHub Sync is using a worker-local company token fallback because plugin secret refs are unavailable in this host.", {
|
|
10296
|
+
companyId: normalizeCompanyId(options.companyId),
|
|
10297
|
+
secretRef: configuredTokenSource.secretRef,
|
|
10298
|
+
error: getErrorMessage(error)
|
|
10299
|
+
});
|
|
10300
|
+
return configuredTokenSource.fallbackToken;
|
|
10301
|
+
}
|
|
10302
|
+
throw error;
|
|
10303
|
+
}
|
|
10099
10304
|
}
|
|
10100
10305
|
return configuredTokenSource.token ?? "";
|
|
10101
10306
|
}
|
|
@@ -15553,6 +15758,8 @@ var __testing = {
|
|
|
15553
15758
|
formatPaperclipApiFetchErrorMessage,
|
|
15554
15759
|
hasUnresolvedPaperclipIssueBlocker,
|
|
15555
15760
|
isHealthyMaintainerWaitTransition,
|
|
15761
|
+
resolvePaperclipApiAuthTokens,
|
|
15762
|
+
resolveGithubToken,
|
|
15556
15763
|
resolvePaperclipPullRequestIssueStatus,
|
|
15557
15764
|
resolveSyncTransitionAssignee
|
|
15558
15765
|
};
|
|
@@ -15569,6 +15776,8 @@ var plugin = definePlugin({
|
|
|
15569
15776
|
const normalizedSettings = normalizeSettings(saved);
|
|
15570
15777
|
const config = await getResolvedConfig(ctx);
|
|
15571
15778
|
const githubTokenConfigured = hasConfiguredGithubToken(normalizedSettings, config, requestedCompanyId);
|
|
15779
|
+
const configuredGitHubTokenRef = getConfiguredGitHubTokenRef(config, requestedCompanyId);
|
|
15780
|
+
const savedGitHubTokenRef = getSavedGitHubTokenRef(normalizedSettings, requestedCompanyId);
|
|
15572
15781
|
const configuredBoardTokenRef = getConfiguredPaperclipBoardApiTokenRef(config, requestedCompanyId);
|
|
15573
15782
|
const savedBoardTokenRef = getSavedPaperclipBoardApiTokenRef(normalizedSettings, requestedCompanyId);
|
|
15574
15783
|
const settingsForResponse = sanitizeSettingsForCurrentSetup(
|
|
@@ -15590,6 +15799,8 @@ var plugin = definePlugin({
|
|
|
15590
15799
|
paperclipApiBaseUrlConfigured: Boolean(normalizePaperclipApiBaseUrl(config.paperclipApiBaseUrl)),
|
|
15591
15800
|
githubTokenConfigured,
|
|
15592
15801
|
paperclipBoardAccessConfigured: requestedCompanyId ? hasConfiguredPaperclipBoardAccess(settingsForResponse, config, requestedCompanyId) : hasConfiguredPaperclipBoardAccessForMappings(settingsForResponse, config, scopedMappings),
|
|
15802
|
+
...savedGitHubTokenRef ? { githubTokenConfigSyncRef: savedGitHubTokenRef } : {},
|
|
15803
|
+
githubTokenNeedsConfigSync: Boolean(savedGitHubTokenRef && configuredGitHubTokenRef !== savedGitHubTokenRef),
|
|
15593
15804
|
...savedBoardTokenRef ? { paperclipBoardAccessConfigSyncRef: savedBoardTokenRef } : {},
|
|
15594
15805
|
paperclipBoardAccessNeedsConfigSync: Boolean(savedBoardTokenRef && !configuredBoardTokenRef)
|
|
15595
15806
|
};
|
|
@@ -15792,6 +16003,7 @@ var plugin = definePlugin({
|
|
|
15792
16003
|
throw new Error("A company id is required to update Paperclip board access.");
|
|
15793
16004
|
}
|
|
15794
16005
|
const nextSecretRef = normalizeSecretRef(record.paperclipBoardApiTokenRef);
|
|
16006
|
+
const nextBoardApiToken = normalizeGitHubToken(record.paperclipBoardApiToken);
|
|
15795
16007
|
const nextPaperclipBoardApiTokenRefs = {
|
|
15796
16008
|
...previous.paperclipBoardApiTokenRefs ?? {}
|
|
15797
16009
|
};
|
|
@@ -15803,10 +16015,18 @@ var plugin = definePlugin({
|
|
|
15803
16015
|
};
|
|
15804
16016
|
if (nextSecretRef) {
|
|
15805
16017
|
nextPaperclipBoardApiTokenRefs[companyId] = nextSecretRef;
|
|
16018
|
+
if (nextBoardApiToken) {
|
|
16019
|
+
if (await shouldSeedExternalPaperclipBoardTokenFallback(ctx, companyId, nextSecretRef)) {
|
|
16020
|
+
await writeExternalCompanyPaperclipBoardApiTokenFallback(ctx, companyId, nextBoardApiToken);
|
|
16021
|
+
} else {
|
|
16022
|
+
await clearExternalCompanyPaperclipBoardApiTokenFallback(ctx, companyId);
|
|
16023
|
+
}
|
|
16024
|
+
}
|
|
15806
16025
|
} else {
|
|
15807
16026
|
delete nextPaperclipBoardApiTokenRefs[companyId];
|
|
15808
16027
|
delete nextPaperclipBoardAccessIdentityByCompanyId[companyId];
|
|
15809
16028
|
delete nextPaperclipBoardAccessUserIdByCompanyId[companyId];
|
|
16029
|
+
await clearExternalCompanyPaperclipBoardApiTokenFallback(ctx, companyId);
|
|
15810
16030
|
}
|
|
15811
16031
|
if ("paperclipBoardAccessIdentity" in record) {
|
|
15812
16032
|
const nextIdentityLabel = normalizeOptionalString2(record.paperclipBoardAccessIdentity);
|
|
@@ -15856,6 +16076,44 @@ var plugin = definePlugin({
|
|
|
15856
16076
|
}
|
|
15857
16077
|
return validateGithubToken(ctx, trimmedToken);
|
|
15858
16078
|
});
|
|
16079
|
+
ctx.actions.register("settings.ensureGitHubTokenAvailable", async (input) => {
|
|
16080
|
+
const record = input && typeof input === "object" ? input : {};
|
|
16081
|
+
const companyId = normalizeCompanyId(record.companyId);
|
|
16082
|
+
const githubTokenRef = normalizeSecretRef(record.githubTokenRef);
|
|
16083
|
+
const token = normalizeGitHubToken(record.token);
|
|
16084
|
+
if (!companyId) {
|
|
16085
|
+
throw new Error("Company context is required to verify worker access to the GitHub token.");
|
|
16086
|
+
}
|
|
16087
|
+
if (!githubTokenRef) {
|
|
16088
|
+
throw new Error("A GitHub token secret ref is required to verify worker token access.");
|
|
16089
|
+
}
|
|
16090
|
+
if (!token) {
|
|
16091
|
+
throw new Error("A validated GitHub token is required to prepare the worker token fallback.");
|
|
16092
|
+
}
|
|
16093
|
+
try {
|
|
16094
|
+
const resolvedToken = (await ctx.secrets.resolve(githubTokenRef)).trim();
|
|
16095
|
+
if (resolvedToken) {
|
|
16096
|
+
return {
|
|
16097
|
+
secretResolvable: true,
|
|
16098
|
+
fallbackStored: false
|
|
16099
|
+
};
|
|
16100
|
+
}
|
|
16101
|
+
} catch (error) {
|
|
16102
|
+
if (!isPluginSecretReferenceDisabledError(error)) {
|
|
16103
|
+
throw error;
|
|
16104
|
+
}
|
|
16105
|
+
await writeExternalCompanyGitHubTokenFallback(ctx, companyId, token);
|
|
16106
|
+
return {
|
|
16107
|
+
secretResolvable: false,
|
|
16108
|
+
fallbackStored: true
|
|
16109
|
+
};
|
|
16110
|
+
}
|
|
16111
|
+
await writeExternalCompanyGitHubTokenFallback(ctx, companyId, token);
|
|
16112
|
+
return {
|
|
16113
|
+
secretResolvable: false,
|
|
16114
|
+
fallbackStored: true
|
|
16115
|
+
};
|
|
16116
|
+
});
|
|
15859
16117
|
ctx.actions.register("project.pullRequests.createIssue", async (input) => {
|
|
15860
16118
|
const record = input && typeof input === "object" ? input : {};
|
|
15861
16119
|
return createProjectPullRequestPaperclipIssue(ctx, record);
|