@cat-factory/app 0.261.1 → 0.261.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/app/components/foundational/FoundationalServiceManager.vue +1 -1
- package/app/components/fragments/FragmentLibraryManager.vue +1 -1
- package/app/components/layout/BoardTopOverlays.vue +6 -0
- package/app/components/layout/GitHubPatPermissionsBanner.vue +224 -0
- package/app/components/skills/SkillLibraryManager.vue +1 -1
- package/app/composables/api/github.ts +7 -0
- package/app/stores/github/probe.ts +97 -0
- package/app/stores/github.spec.ts +109 -1
- package/app/stores/github.ts +26 -42
- package/app/types/github.ts +4 -0
- package/app/utils/connectionWarnings.ts +1 -0
- package/app/utils/vcs.ts +28 -3
- package/i18n/locales/de.json +23 -1
- package/i18n/locales/en.json +41 -1
- package/i18n/locales/es.json +23 -1
- package/i18n/locales/fr.json +23 -1
- package/i18n/locales/he.json +23 -1
- package/i18n/locales/it.json +23 -1
- package/i18n/locales/ja.json +23 -1
- package/i18n/locales/pl.json +23 -1
- package/i18n/locales/tr.json +23 -1
- package/i18n/locales/uk.json +23 -1
- package/package.json +2 -2
|
@@ -62,7 +62,7 @@ watch(
|
|
|
62
62
|
void documents.probe()
|
|
63
63
|
// The GitHub pickers (repo search + tree browser) need the active board's
|
|
64
64
|
// installation state; probe once so they light up when the App is connected.
|
|
65
|
-
void github.
|
|
65
|
+
void github.ensureProbed()
|
|
66
66
|
},
|
|
67
67
|
{ immediate: true },
|
|
68
68
|
)
|
|
@@ -3,6 +3,7 @@ import BoardToolbar from '~/components/layout/BoardToolbar.vue'
|
|
|
3
3
|
import ConnectionStatusBanner from '~/components/layout/ConnectionStatusBanner.vue'
|
|
4
4
|
import SpendWarningBanner from '~/components/layout/SpendWarningBanner.vue'
|
|
5
5
|
import GitHubPatBanner from '~/components/layout/GitHubPatBanner.vue'
|
|
6
|
+
import GitHubPatPermissionsBanner from '~/components/layout/GitHubPatPermissionsBanner.vue'
|
|
6
7
|
import AiProvidersBanner from '~/components/layout/AiProvidersBanner.vue'
|
|
7
8
|
import ProviderConfigBanner from '~/components/layout/ProviderConfigBanner.vue'
|
|
8
9
|
import InfraSetupBanner from '~/components/layout/InfraSetupBanner.vue'
|
|
@@ -68,6 +69,10 @@ const ui = useUiStore()
|
|
|
68
69
|
- Connection status: what is on screen right now may already be stale.
|
|
69
70
|
- Spend exceeded: runs are blocked until the budget moves.
|
|
70
71
|
- GitHub PAT (local mode): every repo-operating step will fail.
|
|
72
|
+
- GitHub PAT permissions: a token IS configured, but it cannot push or open pull
|
|
73
|
+
requests, so every repo-operating step will fail just as surely. Directly after its
|
|
74
|
+
missing-token sibling, which it can never appear beside (that one raises only when
|
|
75
|
+
there is no token, this one only when there is).
|
|
71
76
|
- AI readiness: no usable model source, or the default preset names unavailable models.
|
|
72
77
|
- Infrastructure provider: env/runner-pool wired but missing mandatory config.
|
|
73
78
|
- Infra setup: an executor / test env / storage this deployment needs is undefined, so
|
|
@@ -82,6 +87,7 @@ const ui = useUiStore()
|
|
|
82
87
|
/>
|
|
83
88
|
<SpendWarningBanner />
|
|
84
89
|
<GitHubPatBanner />
|
|
90
|
+
<GitHubPatPermissionsBanner />
|
|
85
91
|
<AiProvidersBanner />
|
|
86
92
|
<ProviderConfigBanner />
|
|
87
93
|
<InfraSetupBanner />
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed, ref } from 'vue'
|
|
3
|
+
import {
|
|
4
|
+
GITHUB_PAT_FINE_GRAINED_PERMISSIONS,
|
|
5
|
+
githubPatCheckNeedsAttention,
|
|
6
|
+
githubPatCheckSource,
|
|
7
|
+
missingGitHubPatCapabilities,
|
|
8
|
+
} from '@cat-factory/contracts'
|
|
9
|
+
import type { GitHubPatCapability, GitHubPatKind } from '~/types/domain'
|
|
10
|
+
import { githubPatRemintUrl } from '~/utils/vcs'
|
|
11
|
+
|
|
12
|
+
// The token a run would authenticate with cannot do what the pipeline needs.
|
|
13
|
+
//
|
|
14
|
+
// This is the board-load half of a warning the backend already logs at boot in local mode: a
|
|
15
|
+
// developer's terminal is easy to miss, and on a HOSTED deployment there is no terminal at all
|
|
16
|
+
// for the case this also covers, where the run initiator's own stored token outranks the App
|
|
17
|
+
// installation. Either way the alternative to saying it here is saying it eight steps into a
|
|
18
|
+
// pipeline as a 403 out of a container, after the run has spent money.
|
|
19
|
+
//
|
|
20
|
+
// It raises on ESTABLISHED blocking gaps only (`githubPatCheckNeedsAttention`). An unreachable
|
|
21
|
+
// GitHub, an advisory-only finding and an unknowable fine-grained permission each render
|
|
22
|
+
// nothing over the board, because none of them is something the reader can act on right now and
|
|
23
|
+
// a banner that appears when nothing is wrong is one people learn to dismiss unread.
|
|
24
|
+
//
|
|
25
|
+
// Positioning/stacking is owned by `BoardTopOverlays`; this renders only its card.
|
|
26
|
+
|
|
27
|
+
const { t } = useI18n()
|
|
28
|
+
const github = useGitHubStore()
|
|
29
|
+
|
|
30
|
+
const dismissed = ref(false)
|
|
31
|
+
const check = computed(() => github.patCheck)
|
|
32
|
+
const show = computed(
|
|
33
|
+
() => !dismissed.value && check.value !== null && githubPatCheckNeedsAttention(check.value),
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
/** The report, when the check produced one. Absent for a token GitHub rejected outright. */
|
|
37
|
+
const report = computed(() => (check.value?.state === 'checked' ? check.value.report : undefined))
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Which claim the card is making. `rejected` is the strictly worse problem (the token does not
|
|
41
|
+
* authenticate at all), so it gets its own copy rather than being folded into "some capability
|
|
42
|
+
* is missing" — every capability would read as missing, which describes the symptom and not the
|
|
43
|
+
* cause.
|
|
44
|
+
*/
|
|
45
|
+
const claim = computed<'rejected' | 'underscoped'>(() =>
|
|
46
|
+
check.value?.state === 'token_rejected' ? 'rejected' : 'underscoped',
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
const missing = computed<GitHubPatCapability[]>(() =>
|
|
50
|
+
report.value ? missingGitHubPatCapabilities(report.value).blocking : [],
|
|
51
|
+
)
|
|
52
|
+
/**
|
|
53
|
+
* Established gaps that do NOT stop a pipeline, listed inside the card but never the reason it
|
|
54
|
+
* opened. Today that is `workflows`: worth fixing while you are on the token page, not worth
|
|
55
|
+
* interrupting a board for on its own.
|
|
56
|
+
*/
|
|
57
|
+
const advisory = computed<GitHubPatCapability[]>(() =>
|
|
58
|
+
report.value ? missingGitHubPatCapabilities(report.value).advisory : [],
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
const CAPABILITY_KEYS: Record<GitHubPatCapability, string> = {
|
|
62
|
+
push: 'layout.githubPatPermissionsBanner.capability.push',
|
|
63
|
+
pullRequests: 'layout.githubPatPermissionsBanner.capability.pullRequests',
|
|
64
|
+
workflows: 'layout.githubPatPermissionsBanner.capability.workflows',
|
|
65
|
+
}
|
|
66
|
+
function capabilityLabel(capability: GitHubPatCapability): string {
|
|
67
|
+
return t(CAPABILITY_KEYS[capability])
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* The kind carried over to the re-mint link. A rejected token was never classified, so it falls
|
|
72
|
+
* back to `unknown` — which lands on the classic form, the only one GitHub lets us pre-fill.
|
|
73
|
+
*/
|
|
74
|
+
const kind = computed<GitHubPatKind>(() => report.value?.kind ?? 'unknown')
|
|
75
|
+
const remintUrl = computed(() =>
|
|
76
|
+
githubPatRemintUrl(kind.value, report.value?.webUrl ?? github.connection?.webUrl),
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Who has to act. A deployment token is replaced by whoever runs the deployment (local mode:
|
|
81
|
+
* the developer at the terminal); an initiator token belongs to the signed-in user and is
|
|
82
|
+
* replaced in their own settings. Sending one to the other's remedy is worse than saying
|
|
83
|
+
* nothing, which is why the source rides the wire rather than being guessed from the shape.
|
|
84
|
+
*
|
|
85
|
+
* Read through the contract's own accessor rather than off `report`, because a REJECTED token
|
|
86
|
+
* produces no report and every state this banner renders carries a source. Deriving it from the
|
|
87
|
+
* report alone left the rejected case falling through to whichever branch the ternary ended on,
|
|
88
|
+
* which told a local developer whose deployment token had expired to replace it in their
|
|
89
|
+
* personal settings: the exact misrouting the wire field exists to prevent.
|
|
90
|
+
*/
|
|
91
|
+
const sourceKey = computed(() =>
|
|
92
|
+
check.value && githubPatCheckSource(check.value) === 'deployment'
|
|
93
|
+
? 'layout.githubPatPermissionsBanner.sourceDeployment'
|
|
94
|
+
: 'layout.githubPatPermissionsBanner.sourceInitiator',
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
/** The fine-grained form takes no prefill, so the permissions have to be named as prose. */
|
|
98
|
+
const fineGrainedPermissions = GITHUB_PAT_FINE_GRAINED_PERMISSIONS.join(', ')
|
|
99
|
+
</script>
|
|
100
|
+
|
|
101
|
+
<template>
|
|
102
|
+
<Transition name="fade">
|
|
103
|
+
<div v-if="show" class="pointer-events-auto w-full max-w-3xl">
|
|
104
|
+
<div
|
|
105
|
+
class="w-full max-w-3xl rounded-2xl border-2 border-red-500/70 bg-red-950/95 p-5 shadow-2xl backdrop-blur"
|
|
106
|
+
role="alert"
|
|
107
|
+
data-testid="github-pat-permissions-banner"
|
|
108
|
+
>
|
|
109
|
+
<div class="flex items-start gap-4">
|
|
110
|
+
<UIcon name="i-lucide-shield-alert" class="mt-0.5 h-9 w-9 shrink-0 text-red-400" />
|
|
111
|
+
<div class="min-w-0 flex-1">
|
|
112
|
+
<div class="flex items-start justify-between gap-3">
|
|
113
|
+
<h2 class="text-lg font-semibold text-red-100">
|
|
114
|
+
{{
|
|
115
|
+
claim === 'rejected'
|
|
116
|
+
? t('layout.githubPatPermissionsBanner.rejectedTitle')
|
|
117
|
+
: t('layout.githubPatPermissionsBanner.title')
|
|
118
|
+
}}
|
|
119
|
+
</h2>
|
|
120
|
+
<UButton
|
|
121
|
+
color="neutral"
|
|
122
|
+
variant="ghost"
|
|
123
|
+
size="xs"
|
|
124
|
+
icon="i-lucide-x"
|
|
125
|
+
:aria-label="t('common.close')"
|
|
126
|
+
@click="
|
|
127
|
+
() => {
|
|
128
|
+
dismissed = true
|
|
129
|
+
}
|
|
130
|
+
"
|
|
131
|
+
/>
|
|
132
|
+
</div>
|
|
133
|
+
|
|
134
|
+
<p class="mt-1 text-sm text-red-200/90">
|
|
135
|
+
{{
|
|
136
|
+
claim === 'rejected'
|
|
137
|
+
? t('layout.githubPatPermissionsBanner.rejectedBody')
|
|
138
|
+
: t('layout.githubPatPermissionsBanner.body')
|
|
139
|
+
}}
|
|
140
|
+
</p>
|
|
141
|
+
|
|
142
|
+
<!-- The established gaps, named one by one. A bare "permissions are missing" leaves
|
|
143
|
+
the reader to guess which box to tick on a form with dozens. -->
|
|
144
|
+
<p v-if="missing.length" class="mt-3 text-sm text-red-100">
|
|
145
|
+
<span class="font-medium">{{ t('layout.githubPatPermissionsBanner.missing') }}</span>
|
|
146
|
+
{{ missing.map(capabilityLabel).join(', ') }}
|
|
147
|
+
</p>
|
|
148
|
+
<p v-if="advisory.length" class="mt-1 text-xs text-red-200/80">
|
|
149
|
+
{{
|
|
150
|
+
t('layout.githubPatPermissionsBanner.alsoMissing', {
|
|
151
|
+
capabilities: advisory.map(capabilityLabel).join(', '),
|
|
152
|
+
})
|
|
153
|
+
}}
|
|
154
|
+
</p>
|
|
155
|
+
|
|
156
|
+
<!-- For a fine-grained token, WHICH repositories it was not granted is the whole
|
|
157
|
+
remedy: the permission list is right and the repository selection is not. -->
|
|
158
|
+
<p v-if="report && report.deniedRepos.length" class="mt-1 text-xs text-red-200/80">
|
|
159
|
+
{{
|
|
160
|
+
t('layout.githubPatPermissionsBanner.deniedRepos', {
|
|
161
|
+
repos: report.deniedRepos.join(', '),
|
|
162
|
+
})
|
|
163
|
+
}}
|
|
164
|
+
</p>
|
|
165
|
+
|
|
166
|
+
<p class="mt-2 text-xs text-red-200/80">{{ t(sourceKey) }}</p>
|
|
167
|
+
|
|
168
|
+
<div class="mt-4">
|
|
169
|
+
<UButton
|
|
170
|
+
:to="remintUrl"
|
|
171
|
+
target="_blank"
|
|
172
|
+
rel="noopener noreferrer"
|
|
173
|
+
color="error"
|
|
174
|
+
variant="solid"
|
|
175
|
+
icon="i-lucide-external-link"
|
|
176
|
+
trailing
|
|
177
|
+
>
|
|
178
|
+
{{
|
|
179
|
+
kind === 'fine_grained'
|
|
180
|
+
? t('layout.githubPatPermissionsBanner.createFineGrained')
|
|
181
|
+
: t('layout.githubPatPermissionsBanner.createClassic')
|
|
182
|
+
}}
|
|
183
|
+
</UButton>
|
|
184
|
+
<!-- The classic form arrives with the scopes ticked; the fine-grained one accepts
|
|
185
|
+
no prefill at all, so its permissions are spelled out. Saying so is the point:
|
|
186
|
+
a link that silently arrived with nothing selected reads as "already done for
|
|
187
|
+
you", which is how the missing permission got there in the first place. -->
|
|
188
|
+
<p class="mt-2 text-xs text-red-300/70">
|
|
189
|
+
{{
|
|
190
|
+
kind === 'fine_grained'
|
|
191
|
+
? t('layout.githubPatPermissionsBanner.fineGrainedHint', {
|
|
192
|
+
permissions: fineGrainedPermissions,
|
|
193
|
+
})
|
|
194
|
+
: t('layout.githubPatPermissionsBanner.classicHint')
|
|
195
|
+
}}
|
|
196
|
+
</p>
|
|
197
|
+
<!-- A fine-grained verdict is a SAMPLE of the linked repositories. Declaring the
|
|
198
|
+
remainder keeps a clean-looking list from reading as a guarantee. -->
|
|
199
|
+
<p v-if="report && report.unprobedRepoCount > 0" class="mt-1 text-xs text-red-300/60">
|
|
200
|
+
{{
|
|
201
|
+
t('layout.githubPatPermissionsBanner.sampled', {
|
|
202
|
+
checked: report.probedRepos.length,
|
|
203
|
+
remaining: report.unprobedRepoCount,
|
|
204
|
+
})
|
|
205
|
+
}}
|
|
206
|
+
</p>
|
|
207
|
+
</div>
|
|
208
|
+
</div>
|
|
209
|
+
</div>
|
|
210
|
+
</div>
|
|
211
|
+
</div>
|
|
212
|
+
</Transition>
|
|
213
|
+
</template>
|
|
214
|
+
|
|
215
|
+
<style scoped>
|
|
216
|
+
.fade-enter-active,
|
|
217
|
+
.fade-leave-active {
|
|
218
|
+
transition: opacity 0.2s ease;
|
|
219
|
+
}
|
|
220
|
+
.fade-enter-from,
|
|
221
|
+
.fade-leave-to {
|
|
222
|
+
opacity: 0;
|
|
223
|
+
}
|
|
224
|
+
</style>
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
createGitHubRepoContract,
|
|
7
7
|
disconnectGitHubContract,
|
|
8
8
|
getGitHubConnectionContract,
|
|
9
|
+
getGitHubPatCheckContract,
|
|
9
10
|
getGitHubInstallUrlContract,
|
|
10
11
|
listGitHubAvailableReposContract,
|
|
11
12
|
listGitHubBranchesContract,
|
|
@@ -52,6 +53,12 @@ export function githubApi({ send, ws }: ApiContext) {
|
|
|
52
53
|
getGitHubConnection: (workspaceId: string) =>
|
|
53
54
|
send(getGitHubConnectionContract, { pathPrefix: ws(workspaceId) }),
|
|
54
55
|
|
|
56
|
+
// What the personal access token this workspace's runs would authenticate with can actually
|
|
57
|
+
// do. Answers `not_applicable` (not a 404/503) on a deployment that uses a GitHub App or no
|
|
58
|
+
// PAT at all, so the caller makes one unconditional call on board load.
|
|
59
|
+
getGitHubPatCheck: (workspaceId: string) =>
|
|
60
|
+
send(getGitHubPatCheckContract, { pathPrefix: ws(workspaceId) }),
|
|
61
|
+
|
|
55
62
|
listGitHubInstallations: (workspaceId: string) =>
|
|
56
63
|
send(listGitHubInstallationsContract, { pathPrefix: ws(workspaceId) }),
|
|
57
64
|
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import type { Ref } from 'vue'
|
|
2
|
+
import type { GitHubPatCheck } from '~/types/domain'
|
|
3
|
+
import { useSingleFlightProbe } from '~/composables/useSingleFlightProbe'
|
|
4
|
+
import type { GitHubStoreContext } from '~/stores/github/context'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* The board-load probe: everything the store learns about the deployment's VCS setup in one round
|
|
8
|
+
* trip, before anything is clicked.
|
|
9
|
+
*
|
|
10
|
+
* Three questions, deliberately not three failure modes:
|
|
11
|
+
* - Is the integration there at all, and what is bound? (`available` + `connection`)
|
|
12
|
+
* - What could be connected, for the not-connected UI? (`connectOptions`)
|
|
13
|
+
* - Can the token a run would use actually push? (`patCheck`)
|
|
14
|
+
*
|
|
15
|
+
* Extracted from the store setup when the credential check pushed it past the function-size
|
|
16
|
+
* ratchet, and it is the right seam rather than a convenient one: these three reads share a
|
|
17
|
+
* lifecycle (fired together on board open, reset together on workspace switch) and nothing else in
|
|
18
|
+
* the store does.
|
|
19
|
+
*
|
|
20
|
+
* The credential check is the odd one out in TWO ways, and both are why it is single-flighted
|
|
21
|
+
* SEPARATELY rather than being a third branch of `runProbe`:
|
|
22
|
+
*
|
|
23
|
+
* - It is the only read that leaves the deployment. The others answer from local rows in
|
|
24
|
+
* milliseconds; this one waits on GitHub, up to a `GET /user` plus a repository read each. So
|
|
25
|
+
* it is started beside them and never awaited by the caller: a modal that awaits `probe()` to
|
|
26
|
+
* learn whether the integration is available would otherwise sit behind a slow or unreachable
|
|
27
|
+
* GitHub for as long as those calls take, to render a banner it does not own.
|
|
28
|
+
* - It is a DIAGNOSTIC, not data any caller reads, so it follows the DOOR rather than the batch.
|
|
29
|
+
* `ensureProbed()` (the on-board-open fan-out) checks at most once per board; `probe()` (the
|
|
30
|
+
* deliberate-refresh door) re-checks, because the surfaces that force a refresh are the ones
|
|
31
|
+
* that just changed what the answer depends on: linking a repository to a service frame is
|
|
32
|
+
* what turns "this board targets no GitHub repository" into a verdict at all. A panel that
|
|
33
|
+
* merely wants to know whether the integration is available belongs on `ensureProbed()`, and
|
|
34
|
+
* the ones whose own comments said "probe once so the pickers light up" were moved onto it.
|
|
35
|
+
*/
|
|
36
|
+
export function createGitHubProbe(
|
|
37
|
+
ctx: GitHubStoreContext,
|
|
38
|
+
patCheck: Ref<GitHubPatCheck | null>,
|
|
39
|
+
): { probe: () => Promise<void>; ensureProbed: () => Promise<void> } {
|
|
40
|
+
const { api, workspace, available, connection, connectOptions } = ctx
|
|
41
|
+
|
|
42
|
+
async function runPatCheck(): Promise<void> {
|
|
43
|
+
// Which board asked, captured BEFORE the await: a workspace switch mid-flight must not land
|
|
44
|
+
// this board's verdict on the next one's banner. The single-flight wrapper re-keys on the id
|
|
45
|
+
// but cannot un-assign a value the run already wrote.
|
|
46
|
+
const askedFor = workspace.workspaceId
|
|
47
|
+
if (!askedFor) return
|
|
48
|
+
// A failure leaves the previous value alone rather than clearing it: `null` means "not
|
|
49
|
+
// answered", which the banner reads as nothing to say, and overwriting a real verdict with
|
|
50
|
+
// it would silently retract a warning the reader has not acted on.
|
|
51
|
+
const check = await api.getGitHubPatCheck(askedFor).catch(() => null)
|
|
52
|
+
if (check && workspace.workspaceId === askedFor) patCheck.value = check
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const patProbe = useSingleFlightProbe(runPatCheck, () => workspace.workspaceId)
|
|
56
|
+
|
|
57
|
+
async function runConnectionReads(): Promise<void> {
|
|
58
|
+
if (!workspace.workspaceId) return
|
|
59
|
+
try {
|
|
60
|
+
const [{ connection: conn }, options] = await Promise.all([
|
|
61
|
+
api.getGitHubConnection(workspace.requireId()),
|
|
62
|
+
api
|
|
63
|
+
.listVcsConnectOptions(workspace.requireId())
|
|
64
|
+
.then((r) => r.options)
|
|
65
|
+
.catch(() => []),
|
|
66
|
+
])
|
|
67
|
+
available.value = true
|
|
68
|
+
connection.value = conn
|
|
69
|
+
connectOptions.value = options
|
|
70
|
+
} catch {
|
|
71
|
+
// 503 (integration disabled) or any error → hide the UI entry points.
|
|
72
|
+
available.value = false
|
|
73
|
+
connection.value = null
|
|
74
|
+
connectOptions.value = []
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Single-flight the connection reads (app-startup initiative, item 12): `probe()` still re-reads
|
|
79
|
+
// on demand, but the on-board-open callers (the board page's onboarding gate + the SideBar) use
|
|
80
|
+
// `ensureProbed()` so their duplicate fire collapses to one request per board. A workspace switch
|
|
81
|
+
// (new id) re-probes.
|
|
82
|
+
const connectionProbe = useSingleFlightProbe(runConnectionReads, () => workspace.workspaceId)
|
|
83
|
+
|
|
84
|
+
// The credential check rides the same DOOR the caller opened but never its await, so a slow or
|
|
85
|
+
// unreachable GitHub delays nothing a caller is waiting on. Awaiting only the connection reads
|
|
86
|
+
// is what keeps `await github.probe()` a local-row read, which is what its callers treat it as.
|
|
87
|
+
return {
|
|
88
|
+
probe: () => {
|
|
89
|
+
void patProbe.probe()
|
|
90
|
+
return connectionProbe.probe()
|
|
91
|
+
},
|
|
92
|
+
ensureProbed: () => {
|
|
93
|
+
void patProbe.ensureProbed()
|
|
94
|
+
return connectionProbe.ensureProbed()
|
|
95
|
+
},
|
|
96
|
+
}
|
|
97
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { describe, it, expect, vi, type Mock } from 'vitest'
|
|
2
2
|
import { useGitHubStore } from '~/stores/github'
|
|
3
3
|
import { useWorkspaceStore } from '~/stores/workspace'
|
|
4
|
-
import type { GitHubConnection, GitHubRepo, VcsConnectOption } from '~/types/domain'
|
|
4
|
+
import type { GitHubConnection, GitHubPatCheck, GitHubRepo, VcsConnectOption } from '~/types/domain'
|
|
5
5
|
|
|
6
6
|
// The VCS connect surface of the (single, GitHub-shaped) repo store: which connect methods the
|
|
7
7
|
// deployment offers, the per-workspace GitLab PAT connect, and the provider-routed disconnect.
|
|
@@ -29,6 +29,7 @@ function stubApi<T extends Record<string, Mock>>(api: T) {
|
|
|
29
29
|
listGitHubRepos: vi.fn().mockResolvedValue([]),
|
|
30
30
|
listGitHubPullRequests: vi.fn().mockResolvedValue([]),
|
|
31
31
|
listGitHubIssues: vi.fn().mockResolvedValue([]),
|
|
32
|
+
getGitHubPatCheck: vi.fn().mockResolvedValue({ state: 'not_applicable' }),
|
|
32
33
|
...api,
|
|
33
34
|
}
|
|
34
35
|
vi.stubGlobal('useApi', () => full)
|
|
@@ -285,3 +286,110 @@ describe('github store — repo web links', () => {
|
|
|
285
286
|
)
|
|
286
287
|
})
|
|
287
288
|
})
|
|
289
|
+
|
|
290
|
+
// The credential check rides the same probe DOOR, but neither the same failure nor the same
|
|
291
|
+
// await. Local mode reaches GitHub with a personal access token and wires no App module, so the
|
|
292
|
+
// connection read 503s exactly where this check matters most; sharing that catch would have
|
|
293
|
+
// discarded the answer there. And it is the only read that leaves the deployment, so a caller
|
|
294
|
+
// awaiting `probe()` must never end up waiting on GitHub.
|
|
295
|
+
describe('github store — GitHub PAT credential check', () => {
|
|
296
|
+
const REPORT: GitHubPatCheck = {
|
|
297
|
+
state: 'checked',
|
|
298
|
+
report: {
|
|
299
|
+
source: 'deployment',
|
|
300
|
+
kind: 'classic',
|
|
301
|
+
capabilities: { push: 'missing', pullRequests: 'missing', workflows: 'missing' },
|
|
302
|
+
probedRepos: [],
|
|
303
|
+
deniedRepos: [],
|
|
304
|
+
unprobedRepoCount: 0,
|
|
305
|
+
webUrl: 'https://github.com',
|
|
306
|
+
},
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
it('resolves the check alongside the connection probe', async () => {
|
|
310
|
+
stubApi({
|
|
311
|
+
getGitHubConnection: vi.fn().mockResolvedValue({ connection: connection() }),
|
|
312
|
+
listVcsConnectOptions: vi.fn().mockResolvedValue({ options: [] }),
|
|
313
|
+
getGitHubPatCheck: vi.fn().mockResolvedValue(REPORT),
|
|
314
|
+
})
|
|
315
|
+
const github = storeWithWorkspace()
|
|
316
|
+
|
|
317
|
+
await github.probe()
|
|
318
|
+
|
|
319
|
+
await vi.waitFor(() => expect(github.patCheck).toEqual(REPORT))
|
|
320
|
+
})
|
|
321
|
+
|
|
322
|
+
it('keeps the check when the connection read fails, as it does in local mode', async () => {
|
|
323
|
+
stubApi({
|
|
324
|
+
getGitHubConnection: vi.fn().mockRejectedValue(new Error('503')),
|
|
325
|
+
listVcsConnectOptions: vi.fn().mockResolvedValue({ options: [] }),
|
|
326
|
+
getGitHubPatCheck: vi.fn().mockResolvedValue(REPORT),
|
|
327
|
+
})
|
|
328
|
+
const github = storeWithWorkspace()
|
|
329
|
+
|
|
330
|
+
await github.probe()
|
|
331
|
+
|
|
332
|
+
expect(github.available).toBe(false)
|
|
333
|
+
await vi.waitFor(() => expect(github.patCheck).toEqual(REPORT))
|
|
334
|
+
})
|
|
335
|
+
|
|
336
|
+
// A failed READ is not a verdict: `null` says "not answered", which the banner renders as
|
|
337
|
+
// nothing. Collapsing it onto a clean report would be an all-clear nobody established.
|
|
338
|
+
it('leaves the check unanswered when its own read fails', async () => {
|
|
339
|
+
stubApi({
|
|
340
|
+
getGitHubConnection: vi.fn().mockResolvedValue({ connection: null }),
|
|
341
|
+
listVcsConnectOptions: vi.fn().mockResolvedValue({ options: [] }),
|
|
342
|
+
getGitHubPatCheck: vi.fn().mockRejectedValue(new Error('500')),
|
|
343
|
+
})
|
|
344
|
+
const github = storeWithWorkspace()
|
|
345
|
+
|
|
346
|
+
await github.probe()
|
|
347
|
+
|
|
348
|
+
expect(github.patCheck).toBeNull()
|
|
349
|
+
})
|
|
350
|
+
|
|
351
|
+
// The reason it is not awaited: two modals block their open on `probe()`, and every other
|
|
352
|
+
// read behind it answers from local rows. Awaited, an unreachable GitHub held those modals
|
|
353
|
+
// for the full outbound timeout to settle a banner they do not render.
|
|
354
|
+
it('does not make callers wait on the outbound check', async () => {
|
|
355
|
+
let settleCheck = (_: GitHubPatCheck) => {}
|
|
356
|
+
stubApi({
|
|
357
|
+
getGitHubConnection: vi.fn().mockResolvedValue({ connection: connection() }),
|
|
358
|
+
listVcsConnectOptions: vi.fn().mockResolvedValue({ options: [] }),
|
|
359
|
+
getGitHubPatCheck: vi.fn().mockReturnValue(
|
|
360
|
+
new Promise<GitHubPatCheck>((resolve) => {
|
|
361
|
+
settleCheck = resolve
|
|
362
|
+
}),
|
|
363
|
+
),
|
|
364
|
+
})
|
|
365
|
+
const github = storeWithWorkspace()
|
|
366
|
+
|
|
367
|
+
await github.probe()
|
|
368
|
+
|
|
369
|
+
expect(github.available).toBe(true)
|
|
370
|
+
expect(github.patCheck).toBeNull()
|
|
371
|
+
settleCheck(REPORT)
|
|
372
|
+
await vi.waitFor(() => expect(github.patCheck).toEqual(REPORT))
|
|
373
|
+
})
|
|
374
|
+
|
|
375
|
+
// The on-board-open fan-out fires the probe from several places at once. The credential check
|
|
376
|
+
// spends the user's GitHub rate limit, so it collapses to one per board rather than one per
|
|
377
|
+
// caller — while `probe()`, the deliberate-refresh door, still re-checks, because the surfaces
|
|
378
|
+
// that force a refresh are the ones that just changed what the answer depends on.
|
|
379
|
+
it('checks once per board across the on-open fan-out, and again on a deliberate refresh', async () => {
|
|
380
|
+
const getGitHubPatCheck = vi.fn().mockResolvedValue(REPORT)
|
|
381
|
+
stubApi({
|
|
382
|
+
getGitHubConnection: vi.fn().mockResolvedValue({ connection: connection() }),
|
|
383
|
+
listVcsConnectOptions: vi.fn().mockResolvedValue({ options: [] }),
|
|
384
|
+
getGitHubPatCheck,
|
|
385
|
+
})
|
|
386
|
+
const github = storeWithWorkspace()
|
|
387
|
+
|
|
388
|
+
await Promise.all([github.ensureProbed(), github.ensureProbed()])
|
|
389
|
+
await github.ensureProbed()
|
|
390
|
+
await vi.waitFor(() => expect(getGitHubPatCheck).toHaveBeenCalledTimes(1))
|
|
391
|
+
|
|
392
|
+
await github.probe()
|
|
393
|
+
await vi.waitFor(() => expect(getGitHubPatCheck).toHaveBeenCalledTimes(2))
|
|
394
|
+
})
|
|
395
|
+
})
|
package/app/stores/github.ts
CHANGED
|
@@ -6,6 +6,7 @@ import type {
|
|
|
6
6
|
GitHubConnection,
|
|
7
7
|
GitHubInstallationOption,
|
|
8
8
|
GitHubIssue,
|
|
9
|
+
GitHubPatCheck,
|
|
9
10
|
GitHubPullRequest,
|
|
10
11
|
GitHubRepo,
|
|
11
12
|
RepoTreeEntry,
|
|
@@ -13,12 +14,12 @@ import type {
|
|
|
13
14
|
VcsProvider,
|
|
14
15
|
} from '~/types/domain'
|
|
15
16
|
import { branchWebUrl, issueWebUrl, pullWebUrl, repoWebUrl } from '~/utils/vcs'
|
|
16
|
-
import { useSingleFlightProbe } from '~/composables/useSingleFlightProbe'
|
|
17
17
|
import { useUpsertList } from '~/composables/useUpsertList'
|
|
18
18
|
import { useWorkspaceStore } from '~/stores/workspace'
|
|
19
19
|
import { useServicesStore } from '~/stores/services'
|
|
20
20
|
import { pullKey, type GitHubStoreContext } from '~/stores/github/context'
|
|
21
21
|
import { createGitHubConnectionActions } from '~/stores/github/connection'
|
|
22
|
+
import { createGitHubProbe } from '~/stores/github/probe'
|
|
22
23
|
import { createGitHubRepoActions } from '~/stores/github/repoActions'
|
|
23
24
|
import { createVcsConnectActions, createVcsProviderViews } from '~/stores/github/vcsConnect'
|
|
24
25
|
|
|
@@ -41,6 +42,13 @@ export const useGitHubStore = defineStore('github', () => {
|
|
|
41
42
|
const connection = ref<GitHubConnection | null>(null)
|
|
42
43
|
/** The connect surfaces this deployment serves; resolved by the probe alongside `connection`. */
|
|
43
44
|
const connectOptions = ref<VcsConnectOption[]>([])
|
|
45
|
+
/**
|
|
46
|
+
* What the personal access token this workspace's runs would use can actually do, resolved by
|
|
47
|
+
* the probe. `null` = not answered (unprobed, or the read failed); the check's own
|
|
48
|
+
* `not_applicable` state is what "there is no PAT here" looks like. The two are kept apart
|
|
49
|
+
* because only the second is a fact.
|
|
50
|
+
*/
|
|
51
|
+
const patCheck = ref<GitHubPatCheck | null>(null)
|
|
44
52
|
/** Discovered App installations for the connect picker; loaded on demand. */
|
|
45
53
|
const installations = ref<GitHubInstallationOption[]>([])
|
|
46
54
|
const loadingInstallations = ref(false)
|
|
@@ -124,37 +132,6 @@ export const useGitHubStore = defineStore('github', () => {
|
|
|
124
132
|
return branchWebUrl(providerOfRepo(repoGithubId), repoUrl(repoGithubId), branch)
|
|
125
133
|
}
|
|
126
134
|
|
|
127
|
-
/**
|
|
128
|
-
* Probe the integration: resolves `available`, the current connection, and which connect
|
|
129
|
-
* surfaces the deployment serves. The capability read rides the same round trip (it is what
|
|
130
|
-
* the not-connected UI renders from), and degrades to "no connect surface" on its own.
|
|
131
|
-
*/
|
|
132
|
-
async function runProbe() {
|
|
133
|
-
if (!workspace.workspaceId) return
|
|
134
|
-
try {
|
|
135
|
-
const [{ connection: conn }, options] = await Promise.all([
|
|
136
|
-
api.getGitHubConnection(workspace.requireId()),
|
|
137
|
-
api
|
|
138
|
-
.listVcsConnectOptions(workspace.requireId())
|
|
139
|
-
.then((r) => r.options)
|
|
140
|
-
.catch(() => []),
|
|
141
|
-
])
|
|
142
|
-
available.value = true
|
|
143
|
-
connection.value = conn
|
|
144
|
-
connectOptions.value = options
|
|
145
|
-
} catch {
|
|
146
|
-
// 503 (integration disabled) or any error → hide the UI entry points.
|
|
147
|
-
available.value = false
|
|
148
|
-
connection.value = null
|
|
149
|
-
connectOptions.value = []
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
// Single-flight the probe (app-startup initiative, item 12): `probe()` still re-reads on demand,
|
|
153
|
-
// but the on-board-open callers (the board page's onboarding gate + the SideBar) use
|
|
154
|
-
// `ensureProbed()` so their duplicate fire collapses to one request per board. A workspace switch
|
|
155
|
-
// (new id) re-probes.
|
|
156
|
-
const { probe, ensureProbed } = useSingleFlightProbe(runProbe, () => workspace.workspaceId)
|
|
157
|
-
|
|
158
135
|
/** Load the cached repos, pull requests and issues for the workspace. */
|
|
159
136
|
async function load() {
|
|
160
137
|
if (!connected.value) return
|
|
@@ -173,16 +150,6 @@ export const useGitHubStore = defineStore('github', () => {
|
|
|
173
150
|
}
|
|
174
151
|
}
|
|
175
152
|
|
|
176
|
-
/**
|
|
177
|
-
* Ensure the projection (repos/PRs/issues) is loaded at least once — for views
|
|
178
|
-
* that need it without opening the GitHub panel (e.g. the inspector's repo link).
|
|
179
|
-
* Probes the integration first if it hasn't been yet.
|
|
180
|
-
*/
|
|
181
|
-
async function ensureLoaded() {
|
|
182
|
-
if (available.value === null) await probe()
|
|
183
|
-
if (connected.value && repos.value.length === 0) await load()
|
|
184
|
-
}
|
|
185
|
-
|
|
186
153
|
/** Full file listing per repo (recursive tree), cached by GitHub numeric id. */
|
|
187
154
|
const repoFiles = ref<Record<number, RepoTreeEntry[]>>({})
|
|
188
155
|
|
|
@@ -211,6 +178,21 @@ export const useGitHubStore = defineStore('github', () => {
|
|
|
211
178
|
connected,
|
|
212
179
|
load,
|
|
213
180
|
}
|
|
181
|
+
// The board-load probe (integration availability + the bound connection + the connect options +
|
|
182
|
+
// the credential check). Built from the context rather than inline, so this setup stays within
|
|
183
|
+
// the function-size ratchet the credential check pushed it past.
|
|
184
|
+
const { probe, ensureProbed } = createGitHubProbe(context, patCheck)
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Ensure the projection (repos/PRs/issues) is loaded at least once — for views
|
|
188
|
+
* that need it without opening the GitHub panel (e.g. the inspector's repo link).
|
|
189
|
+
* Probes the integration first if it hasn't been yet.
|
|
190
|
+
*/
|
|
191
|
+
async function ensureLoaded() {
|
|
192
|
+
if (available.value === null) await probe()
|
|
193
|
+
if (connected.value && repos.value.length === 0) await load()
|
|
194
|
+
}
|
|
195
|
+
|
|
214
196
|
const connectionActions = createGitHubConnectionActions(context)
|
|
215
197
|
const repoActions = createGitHubRepoActions(context)
|
|
216
198
|
const vcsConnectActions = createVcsConnectActions(context)
|
|
@@ -227,6 +209,7 @@ export const useGitHubStore = defineStore('github', () => {
|
|
|
227
209
|
available.value = null
|
|
228
210
|
connection.value = null
|
|
229
211
|
connectOptions.value = []
|
|
212
|
+
patCheck.value = null
|
|
230
213
|
installations.value = []
|
|
231
214
|
repos.value = []
|
|
232
215
|
availableRepos.value = []
|
|
@@ -240,6 +223,7 @@ export const useGitHubStore = defineStore('github', () => {
|
|
|
240
223
|
available,
|
|
241
224
|
connection,
|
|
242
225
|
connectOptions,
|
|
226
|
+
patCheck,
|
|
243
227
|
installations,
|
|
244
228
|
loadingInstallations,
|
|
245
229
|
repos,
|
package/app/types/github.ts
CHANGED
|
@@ -20,4 +20,5 @@ export const CONNECTION_WARNING_KEYS: Record<ConnectionWarningCode, string> = {
|
|
|
20
20
|
'settings.providerConnection.test.warnings.github_pat_scopes_beyond_need',
|
|
21
21
|
github_pat_scope_unreadable:
|
|
22
22
|
'settings.providerConnection.test.warnings.github_pat_scope_unreadable',
|
|
23
|
+
github_pat_no_scopes: 'settings.providerConnection.test.warnings.github_pat_no_scopes',
|
|
23
24
|
}
|
package/app/utils/vcs.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { GITHUB_TOKEN_CREATE_PATHS, githubPatCreateUrl } from '@cat-factory/contracts'
|
|
2
|
+
import type { GitHubConnection, GitHubPatKind, VcsProvider } from '~/types/domain'
|
|
2
3
|
|
|
3
4
|
// ---------------------------------------------------------------------------
|
|
4
5
|
// Shared VCS provider presentation. The platform's repo DATA is provider-neutral (one
|
|
@@ -42,9 +43,14 @@ const VCS_PROVIDER_PUBLIC_WEB_URLS: Record<VcsProvider, string> = {
|
|
|
42
43
|
gitlab: 'https://gitlab.com',
|
|
43
44
|
}
|
|
44
45
|
|
|
45
|
-
/**
|
|
46
|
+
/**
|
|
47
|
+
* Where a user creates a personal access token, relative to the instance's web root. GitHub's
|
|
48
|
+
* comes from `@cat-factory/contracts` rather than being spelled again here: the credential
|
|
49
|
+
* banner's PRE-FILLED re-mint link is built from that same map, and the unscoped connect-box
|
|
50
|
+
* link below has to land on the same page.
|
|
51
|
+
*/
|
|
46
52
|
const TOKEN_SETTINGS_PATHS: Record<VcsProvider, string> = {
|
|
47
|
-
github:
|
|
53
|
+
github: GITHUB_TOKEN_CREATE_PATHS.classic,
|
|
48
54
|
gitlab: '/-/user_settings/personal_access_tokens',
|
|
49
55
|
}
|
|
50
56
|
|
|
@@ -85,6 +91,25 @@ export function vcsTokenCreateUrl(provider: VcsProvider, webUrl?: string | null)
|
|
|
85
91
|
return `${root(webUrl || VCS_PROVIDER_PUBLIC_WEB_URLS[provider])}${TOKEN_SETTINGS_PATHS[provider]}`
|
|
86
92
|
}
|
|
87
93
|
|
|
94
|
+
/**
|
|
95
|
+
* Where the credential banner sends someone to REPLACE a GitHub token that cannot do what their
|
|
96
|
+
* runs need, pre-filled as far as GitHub allows.
|
|
97
|
+
*
|
|
98
|
+
* The `kind` is the kind of the token being replaced, so a deployment that standardised on
|
|
99
|
+
* fine-grained tokens is not pushed back to a classic one by a warning. When the check never got
|
|
100
|
+
* far enough to classify (GitHub rejected the token outright), the caller passes `'unknown'` and
|
|
101
|
+
* lands on the form that CAN be pre-filled.
|
|
102
|
+
*
|
|
103
|
+
* Shares {@link vcsTokenCreateUrl}'s public-host fallback for the same stated reason: this is a
|
|
104
|
+
* settings page, so being wrong costs one noticed click, unlike a repository link.
|
|
105
|
+
*/
|
|
106
|
+
export function githubPatRemintUrl(kind: GitHubPatKind, webUrl?: string | null): string {
|
|
107
|
+
return githubPatCreateUrl(kind, {
|
|
108
|
+
webUrl: webUrl || VCS_PROVIDER_PUBLIC_WEB_URLS.github,
|
|
109
|
+
description: 'cat-factory',
|
|
110
|
+
})
|
|
111
|
+
}
|
|
112
|
+
|
|
88
113
|
/**
|
|
89
114
|
* The App installation's settings page, where a user grants it access to a repository it
|
|
90
115
|
* can't see yet — or `undefined` when the connection is not a GitHub-App one.
|
package/i18n/locales/de.json
CHANGED
|
@@ -388,7 +388,8 @@
|
|
|
388
388
|
"runner_manifest_no_status_path": "Kein Statuspfad: Jede Abfrage wird als weiterhin laufend gelesen. Ein Job kann daher nur enden, wenn das Abfragebudget des Laufs aufgebraucht ist.",
|
|
389
389
|
"github_pat_classic_account_wide": "Dies ist ein klassisches Token mit dem Bereich 'repo': Es erreicht jedes Repository, in das du pushen kannst, auch solche, in denen die GitHub-App dieses Arbeitsbereichs nie installiert wurde. Ausführungen, die du startest, nutzen es bevorzugt vor der App. Ein fein abgestuftes Token, das auf die Repositories dieser Installation begrenzt ist, ist enger gefasst.",
|
|
390
390
|
"github_pat_scopes_beyond_need": "Dieses Token gewährt Berechtigungen, die cat-factory nie nutzt. Sie zu entfernen kostet nichts und verkleinert das, was eine kompromittierte Ausführung erreichen könnte.",
|
|
391
|
-
"github_pat_scope_unreadable": "GitHub hat dieses Token akzeptiert, aber keine Bereiche dafür gemeldet, daher lässt sich seine Reichweite hier nicht anzeigen. Prüfe in deinen GitHub-Token-Einstellungen, was es gewährt."
|
|
391
|
+
"github_pat_scope_unreadable": "GitHub hat dieses Token akzeptiert, aber keine Bereiche dafür gemeldet, daher lässt sich seine Reichweite hier nicht anzeigen. Prüfe in deinen GitHub-Token-Einstellungen, was es gewährt.",
|
|
392
|
+
"github_pat_no_scopes": "GitHub meldet für dieses klassische Token keine Scopes, es kann also nur öffentliche Daten lesen. Läufe, die damit klonen, pushen oder einen Pull Request öffnen, schlagen fehl. Erstellen Sie ein neues Token mit ausgewähltem 'repo' und 'workflow'."
|
|
392
393
|
}
|
|
393
394
|
},
|
|
394
395
|
"toast": {
|
|
@@ -2453,6 +2454,27 @@
|
|
|
2453
2454
|
"createToken": "Ein GitHub-Token erstellen (Scopes vorausgewählt)",
|
|
2454
2455
|
"thenSet": "Setzen Sie dann {envVar} und starten Sie neu."
|
|
2455
2456
|
},
|
|
2457
|
+
"githubPatPermissionsBanner": {
|
|
2458
|
+
"title": "GitHub-Token kann nicht pushen oder Pull Requests öffnen",
|
|
2459
|
+
"rejectedTitle": "GitHub hat das Token Ihrer Läufe abgelehnt",
|
|
2460
|
+
"body": "Hier gestartete Läufe authentifizieren sich mit einem GitHub Personal Access Token, und diesem fehlen Berechtigungen, die die Pipeline braucht. Agentenschritte, die einen Branch pushen, einen Pull Request öffnen oder mergen, werden fehlschlagen.",
|
|
2461
|
+
"rejectedBody": "Das GitHub Personal Access Token, mit dem sich Ihre Läufe authentifizieren, ist ungültig, abgelaufen, widerrufen oder durch eine Organisationsrichtlinie blockiert. Jeder Schritt, der klont, pusht, einen Pull Request öffnet oder merget, schlägt fehl, bis es ersetzt wird.",
|
|
2462
|
+
"missing": "Fehlt:",
|
|
2463
|
+
"alsoMissing": "Fehlt ebenfalls, blockiert aber nur Änderungen an Workflow-Dateien: {capabilities}.",
|
|
2464
|
+
"capability": {
|
|
2465
|
+
"push": "Commits pushen",
|
|
2466
|
+
"pullRequests": "Pull Requests öffnen und mergen",
|
|
2467
|
+
"workflows": "Workflow-Dateien bearbeiten"
|
|
2468
|
+
},
|
|
2469
|
+
"sourceDeployment": "Dies ist das Token, mit dem dieses Deployment konfiguriert ist; es zu ersetzen bedeutet daher, das Deployment zu aktualisieren.",
|
|
2470
|
+
"sourceInitiator": "Dies ist Ihr eigenes gespeichertes Token, das Ihre Läufe bevorzugt vor den Deployment-Zugangsdaten verwenden. Ersetzen Sie es in Ihren persönlichen Einstellungen.",
|
|
2471
|
+
"createClassic": "Ersatz-Token erstellen (Scopes vorausgewählt)",
|
|
2472
|
+
"createFineGrained": "Fein granuliertes Ersatz-Token erstellen",
|
|
2473
|
+
"classicHint": "Der Link öffnet das klassische Token-Formular mit bereits ausgewählten erforderlichen Scopes.",
|
|
2474
|
+
"fineGrainedHint": "Das fein granulierte Formular von GitHub akzeptiert keine Vorauswahl; erteilen Sie diese Repository-Berechtigungen daher selbst: {permissions}.",
|
|
2475
|
+
"sampled": "Gegen {checked} genutzte Repositories geprüft; {remaining} weitere wurden nicht geprüft.",
|
|
2476
|
+
"deniedRepos": "Das Token erreicht diese von Ihren Services genutzten Repositories nicht: {repos}. Erstellen Sie es neu und wählen Sie diese Repositories aus."
|
|
2477
|
+
},
|
|
2456
2478
|
"providerConfigBanner": {
|
|
2457
2479
|
"titleMany": "Anbieter benötigen Konfiguration",
|
|
2458
2480
|
"titleOne": {
|
package/i18n/locales/en.json
CHANGED
|
@@ -2341,6 +2341,45 @@
|
|
|
2341
2341
|
"createToken": "Create a GitHub token (scopes pre-selected)",
|
|
2342
2342
|
"thenSet": "Then set {envVar} and restart."
|
|
2343
2343
|
},
|
|
2344
|
+
"githubPatPermissionsBanner": {
|
|
2345
|
+
"title": "GitHub token cannot push or open pull requests",
|
|
2346
|
+
"rejectedTitle": "GitHub rejected the token your runs use",
|
|
2347
|
+
"body": "Runs started here authenticate with a GitHub personal access token, and this one lacks permissions the pipeline needs. Agent steps that push a branch, open a pull request or merge will fail.",
|
|
2348
|
+
"rejectedBody": "The GitHub personal access token your runs authenticate with is invalid, expired, revoked, or blocked by an organisation policy. Every step that clones, pushes, opens a pull request or merges will fail until it is replaced.",
|
|
2349
|
+
"missing": "Missing:",
|
|
2350
|
+
"alsoMissing": "Also missing, though it only blocks changes to workflow files: {capabilities}.",
|
|
2351
|
+
"capability": {
|
|
2352
|
+
"push": "pushing commits",
|
|
2353
|
+
"pullRequests": "opening and merging pull requests",
|
|
2354
|
+
"workflows": "editing workflow files"
|
|
2355
|
+
},
|
|
2356
|
+
"sourceDeployment": "This is the token this deployment is configured with, so replacing it means updating the deployment.",
|
|
2357
|
+
"sourceInitiator": "This is your own stored token, which your runs use in preference to the deployment credential. Replace it in your personal settings.",
|
|
2358
|
+
"createClassic": "Create a replacement token (scopes pre-selected)",
|
|
2359
|
+
"createFineGrained": "Create a replacement fine-grained token",
|
|
2360
|
+
"classicHint": "The link opens the classic token form with the required scopes already selected.",
|
|
2361
|
+
"fineGrainedHint": "GitHub's fine-grained form accepts no pre-selection, so grant these repository permissions yourself: {permissions}.",
|
|
2362
|
+
"sampled": "Checked against {checked} targeted repositories; {remaining} more were not checked.",
|
|
2363
|
+
"deniedRepos": "The token cannot reach these repositories your services target: {repos}. Re-mint it with those repositories selected.",
|
|
2364
|
+
"@title": {
|
|
2365
|
+
"description": "Banner heading when the configured GitHub personal access token authenticates but lacks a permission the pipeline needs. \"push\" and \"pull request\" are the Git/GitHub terms."
|
|
2366
|
+
},
|
|
2367
|
+
"@rejectedTitle": {
|
|
2368
|
+
"description": "Banner heading for the worse case: GitHub refused the token outright (401/403). Distinct from the missing-permission heading on purpose."
|
|
2369
|
+
},
|
|
2370
|
+
"@alsoMissing": {
|
|
2371
|
+
"description": "{capabilities} is a comma-joined list of capability names from the `capability` group. Shown only beside a blocking finding, never alone."
|
|
2372
|
+
},
|
|
2373
|
+
"@fineGrainedHint": {
|
|
2374
|
+
"description": "{permissions} is a comma-joined list of GitHub's own fine-grained permission identifiers (e.g. contents:write); keep them verbatim, untranslated."
|
|
2375
|
+
},
|
|
2376
|
+
"@sampled": {
|
|
2377
|
+
"description": "Declares that the fine-grained check read a SAMPLE. {checked} and {remaining} are counts of repositories."
|
|
2378
|
+
},
|
|
2379
|
+
"@deniedRepos": {
|
|
2380
|
+
"description": "{repos} is a comma-joined list of GitHub owner/name repository paths; keep them verbatim, untranslated. Shown when a fine-grained token was denied access to repositories the board's services target."
|
|
2381
|
+
}
|
|
2382
|
+
},
|
|
2344
2383
|
"providerConfigBanner": {
|
|
2345
2384
|
"titleMany": "Providers need configuration",
|
|
2346
2385
|
"titleOne": {
|
|
@@ -3074,7 +3113,8 @@
|
|
|
3074
3113
|
"runner_manifest_no_status_path": "No status path: every poll reads as still running, so a job can only end by exhausting the run's poll budget.",
|
|
3075
3114
|
"github_pat_classic_account_wide": "This is a classic token with the 'repo' scope: it reaches every repository you can push to, including ones this workspace's GitHub App was never installed on. Runs you start use it in preference to the App. A fine-grained token limited to this deployment's repositories is narrower.",
|
|
3076
3115
|
"github_pat_scopes_beyond_need": "This token grants permissions cat-factory never uses. Removing them costs nothing and narrows what a compromised run could reach.",
|
|
3077
|
-
"github_pat_scope_unreadable": "GitHub accepted this token but reported no scopes for it, so its reach cannot be shown here. Check what it grants in your GitHub token settings."
|
|
3116
|
+
"github_pat_scope_unreadable": "GitHub accepted this token but reported no scopes for it, so its reach cannot be shown here. Check what it grants in your GitHub token settings.",
|
|
3117
|
+
"github_pat_no_scopes": "GitHub reports no scopes for this classic token, so it can read public data and nothing else. Runs that clone, push or open a pull request with it will fail. Mint a replacement with 'repo' and 'workflow' selected."
|
|
3078
3118
|
}
|
|
3079
3119
|
},
|
|
3080
3120
|
"toast": {
|
package/i18n/locales/es.json
CHANGED
|
@@ -2234,6 +2234,27 @@
|
|
|
2234
2234
|
"createToken": "Crear un token de GitHub (ámbitos preseleccionados)",
|
|
2235
2235
|
"thenSet": "Luego define {envVar} y reinicia."
|
|
2236
2236
|
},
|
|
2237
|
+
"githubPatPermissionsBanner": {
|
|
2238
|
+
"title": "El token de GitHub no puede hacer push ni abrir pull requests",
|
|
2239
|
+
"rejectedTitle": "GitHub rechazó el token que usan tus ejecuciones",
|
|
2240
|
+
"body": "Las ejecuciones iniciadas aquí se autentican con un token de acceso personal de GitHub, y a este le faltan permisos que la canalización necesita. Los pasos de agente que envían una rama, abren una pull request o fusionan fallarán.",
|
|
2241
|
+
"rejectedBody": "El token de acceso personal de GitHub con el que se autentican tus ejecuciones no es válido, ha caducado, fue revocado o está bloqueado por una política de la organización. Todos los pasos que clonan, envían, abren pull requests o fusionan fallarán hasta que lo reemplaces.",
|
|
2242
|
+
"missing": "Falta:",
|
|
2243
|
+
"alsoMissing": "También falta, aunque solo bloquea cambios en archivos de flujo de trabajo: {capabilities}.",
|
|
2244
|
+
"capability": {
|
|
2245
|
+
"push": "enviar commits",
|
|
2246
|
+
"pullRequests": "abrir y fusionar pull requests",
|
|
2247
|
+
"workflows": "editar archivos de flujo de trabajo"
|
|
2248
|
+
},
|
|
2249
|
+
"sourceDeployment": "Este es el token con el que está configurado este despliegue, así que reemplazarlo implica actualizar el despliegue.",
|
|
2250
|
+
"sourceInitiator": "Este es tu propio token almacenado, que tus ejecuciones usan con preferencia sobre la credencial del despliegue. Reemplázalo en tus ajustes personales.",
|
|
2251
|
+
"createClassic": "Crear un token de reemplazo (ámbitos preseleccionados)",
|
|
2252
|
+
"createFineGrained": "Crear un token de reemplazo de permisos detallados",
|
|
2253
|
+
"classicHint": "El enlace abre el formulario de token clásico con los ámbitos necesarios ya seleccionados.",
|
|
2254
|
+
"fineGrainedHint": "El formulario de permisos detallados de GitHub no admite preselección, así que concede tú mismo estos permisos de repositorio: {permissions}.",
|
|
2255
|
+
"sampled": "Se comprobaron {checked} repositorios en uso; otros {remaining} no se comprobaron.",
|
|
2256
|
+
"deniedRepos": "El token no puede acceder a estos repositorios que usan tus servicios: {repos}. Vuelve a generarlo seleccionando esos repositorios."
|
|
2257
|
+
},
|
|
2237
2258
|
"providerConfigBanner": {
|
|
2238
2259
|
"titleMany": "Los proveedores necesitan configuración",
|
|
2239
2260
|
"titleOne": {
|
|
@@ -2763,7 +2784,8 @@
|
|
|
2763
2784
|
"runner_manifest_no_status_path": "Sin ruta de estado: cada sondeo se interpreta como todavía en ejecución, así que un trabajo solo puede terminar agotando el presupuesto de sondeo de la ejecución.",
|
|
2764
2785
|
"github_pat_classic_account_wide": "Es un token clásico con el ámbito 'repo': alcanza todos los repositorios a los que puedes hacer push, incluidos aquellos donde nunca se instaló la App de GitHub de este espacio de trabajo. Las ejecuciones que inicias lo usan con preferencia sobre la App. Un token granular limitado a los repositorios de esta instalación es más estrecho.",
|
|
2765
2786
|
"github_pat_scopes_beyond_need": "Este token concede permisos que cat-factory nunca usa. Quitarlos no cuesta nada y reduce lo que podría alcanzar una ejecución comprometida.",
|
|
2766
|
-
"github_pat_scope_unreadable": "GitHub aceptó este token pero no informó de sus ámbitos, así que aquí no se puede mostrar su alcance. Comprueba lo que concede en la configuración de tokens de GitHub."
|
|
2787
|
+
"github_pat_scope_unreadable": "GitHub aceptó este token pero no informó de sus ámbitos, así que aquí no se puede mostrar su alcance. Comprueba lo que concede en la configuración de tokens de GitHub.",
|
|
2788
|
+
"github_pat_no_scopes": "GitHub no informa de ningún ámbito para este token clásico, así que solo puede leer datos públicos. Las ejecuciones que clonen, envíen cambios o abran una pull request con él fallarán. Genera uno nuevo con 'repo' y 'workflow' seleccionados."
|
|
2767
2789
|
}
|
|
2768
2790
|
},
|
|
2769
2791
|
"toast": {
|
package/i18n/locales/fr.json
CHANGED
|
@@ -2234,6 +2234,27 @@
|
|
|
2234
2234
|
"createToken": "Créer un jeton GitHub (portées présélectionnées)",
|
|
2235
2235
|
"thenSet": "Définissez ensuite {envVar} et redémarrez."
|
|
2236
2236
|
},
|
|
2237
|
+
"githubPatPermissionsBanner": {
|
|
2238
|
+
"title": "Le jeton GitHub ne peut ni pousser ni ouvrir de pull requests",
|
|
2239
|
+
"rejectedTitle": "GitHub a rejeté le jeton utilisé par vos exécutions",
|
|
2240
|
+
"body": "Les exécutions lancées ici s'authentifient avec un jeton d'accès personnel GitHub, et celui-ci n'a pas les autorisations dont le pipeline a besoin. Les étapes d'agent qui poussent une branche, ouvrent une pull request ou fusionnent échoueront.",
|
|
2241
|
+
"rejectedBody": "Le jeton d'accès personnel GitHub avec lequel vos exécutions s'authentifient est invalide, expiré, révoqué ou bloqué par une politique d'organisation. Toute étape qui clone, pousse, ouvre une pull request ou fusionne échouera tant qu'il n'est pas remplacé.",
|
|
2242
|
+
"missing": "Manquant :",
|
|
2243
|
+
"alsoMissing": "Manque également, bien que cela ne bloque que les modifications des fichiers de workflow : {capabilities}.",
|
|
2244
|
+
"capability": {
|
|
2245
|
+
"push": "pousser des commits",
|
|
2246
|
+
"pullRequests": "ouvrir et fusionner des pull requests",
|
|
2247
|
+
"workflows": "modifier les fichiers de workflow"
|
|
2248
|
+
},
|
|
2249
|
+
"sourceDeployment": "C'est le jeton configuré pour ce déploiement ; le remplacer suppose donc de mettre à jour le déploiement.",
|
|
2250
|
+
"sourceInitiator": "C'est votre propre jeton enregistré, que vos exécutions utilisent de préférence aux identifiants du déploiement. Remplacez-le dans vos paramètres personnels.",
|
|
2251
|
+
"createClassic": "Créer un jeton de remplacement (portées présélectionnées)",
|
|
2252
|
+
"createFineGrained": "Créer un jeton de remplacement à portée fine",
|
|
2253
|
+
"classicHint": "Le lien ouvre le formulaire de jeton classique avec les portées requises déjà sélectionnées.",
|
|
2254
|
+
"fineGrainedHint": "Le formulaire à portée fine de GitHub n'accepte aucune présélection : accordez vous-même ces autorisations de dépôt : {permissions}.",
|
|
2255
|
+
"sampled": "Vérifié sur {checked} dépôts utilisés ; {remaining} autres non vérifiés.",
|
|
2256
|
+
"deniedRepos": "Le jeton n'atteint pas ces dépôts utilisés par vos services : {repos}. Régénérez-le en sélectionnant ces dépôts."
|
|
2257
|
+
},
|
|
2237
2258
|
"providerConfigBanner": {
|
|
2238
2259
|
"titleMany": "Les fournisseurs nécessitent une configuration",
|
|
2239
2260
|
"titleOne": {
|
|
@@ -2763,7 +2784,8 @@
|
|
|
2763
2784
|
"runner_manifest_no_status_path": "Aucun chemin de statut : chaque interrogation est lue comme toujours en cours, donc un job ne peut se terminer qu'en épuisant le budget d'interrogation de l'exécution.",
|
|
2764
2785
|
"github_pat_classic_account_wide": "Il s'agit d'un jeton classique avec la portée 'repo' : il atteint tous les dépôts sur lesquels vous pouvez pousser, y compris ceux où l'App GitHub de cet espace de travail n'a jamais été installée. Les exécutions que vous lancez l'utilisent de préférence à l'App. Un jeton à portée fine, limité aux dépôts de cette installation, est plus restreint.",
|
|
2765
2786
|
"github_pat_scopes_beyond_need": "Ce jeton accorde des permissions que cat-factory n'utilise jamais. Les retirer ne coûte rien et réduit ce qu'une exécution compromise pourrait atteindre.",
|
|
2766
|
-
"github_pat_scope_unreadable": "GitHub a accepté ce jeton mais n'a signalé aucune portée, sa portée ne peut donc pas être affichée ici. Vérifiez ce qu'il accorde dans vos paramètres de jetons GitHub."
|
|
2787
|
+
"github_pat_scope_unreadable": "GitHub a accepté ce jeton mais n'a signalé aucune portée, sa portée ne peut donc pas être affichée ici. Vérifiez ce qu'il accorde dans vos paramètres de jetons GitHub.",
|
|
2788
|
+
"github_pat_no_scopes": "GitHub ne signale aucune portée pour ce jeton classique : il ne peut lire que des données publiques. Les exécutions qui clonent, poussent ou ouvrent une pull request avec lui échoueront. Créez-en un nouveau avec 'repo' et 'workflow' sélectionnés."
|
|
2767
2789
|
}
|
|
2768
2790
|
},
|
|
2769
2791
|
"toast": {
|
package/i18n/locales/he.json
CHANGED
|
@@ -2234,6 +2234,27 @@
|
|
|
2234
2234
|
"createToken": "צור אסימון GitHub (ההרשאות נבחרו מראש)",
|
|
2235
2235
|
"thenSet": "לאחר מכן הגדר {envVar} והפעל מחדש."
|
|
2236
2236
|
},
|
|
2237
|
+
"githubPatPermissionsBanner": {
|
|
2238
|
+
"title": "אסימון GitHub אינו יכול לדחוף או לפתוח בקשות משיכה",
|
|
2239
|
+
"rejectedTitle": "GitHub דחה את האסימון שבו משתמשות ההרצות שלך",
|
|
2240
|
+
"body": "הרצות שמתחילות כאן מאמתות באמצעות אסימון גישה אישי של GitHub, ולאסימון הזה חסרות הרשאות שהצינור זקוק להן. שלבי סוכן שדוחפים ענף, פותחים בקשת משיכה או ממזגים ייכשלו.",
|
|
2241
|
+
"rejectedBody": "אסימון הגישה האישי של GitHub שבו מאומתות ההרצות שלך אינו תקף, פג תוקפו, בוטל או נחסם על ידי מדיניות ארגונית. כל שלב שמשכפל, דוחף, פותח בקשת משיכה או ממזג ייכשל עד להחלפתו.",
|
|
2242
|
+
"missing": "חסר:",
|
|
2243
|
+
"alsoMissing": "חסר גם, אף שהדבר חוסם רק שינויים בקובצי תהליכי עבודה: {capabilities}.",
|
|
2244
|
+
"capability": {
|
|
2245
|
+
"push": "דחיפת קומיטים",
|
|
2246
|
+
"pullRequests": "פתיחה ומיזוג של בקשות משיכה",
|
|
2247
|
+
"workflows": "עריכת קובצי תהליכי עבודה"
|
|
2248
|
+
},
|
|
2249
|
+
"sourceDeployment": "זהו האסימון שאיתו מוגדרת הפריסה הזו, ולכן החלפתו משמעה עדכון הפריסה.",
|
|
2250
|
+
"sourceInitiator": "זהו האסימון השמור שלך, שההרצות שלך מעדיפות על פני אישורי הפריסה. החלף אותו בהגדרות האישיות שלך.",
|
|
2251
|
+
"createClassic": "צור אסימון חלופי (ההרשאות נבחרו מראש)",
|
|
2252
|
+
"createFineGrained": "צור אסימון חלופי עם הרשאות מדויקות",
|
|
2253
|
+
"classicHint": "הקישור פותח את טופס האסימון הקלאסי כשההרשאות הנדרשות כבר מסומנות.",
|
|
2254
|
+
"fineGrainedHint": "טופס ההרשאות המדויקות של GitHub אינו תומך בבחירה מראש, לכן הענק בעצמך את הרשאות המאגר הבאות: {permissions}.",
|
|
2255
|
+
"sampled": "נבדק מול {checked} מאגרים שבשימוש; {remaining} נוספים לא נבדקו.",
|
|
2256
|
+
"deniedRepos": "האסימון אינו מגיע למאגרים האלה שהשירותים שלך משתמשים בהם: {repos}. צור אותו מחדש ובחר את המאגרים האלה."
|
|
2257
|
+
},
|
|
2237
2258
|
"providerConfigBanner": {
|
|
2238
2259
|
"titleMany": "ספקים זקוקים להגדרה",
|
|
2239
2260
|
"titleOne": {
|
|
@@ -2964,7 +2985,8 @@
|
|
|
2964
2985
|
"runner_manifest_no_status_path": "אין נתיב סטטוס: כל תשאול נקרא כאילו המשימה עדיין רצה, ולכן משימה יכולה להסתיים רק לאחר ניצול כל תקציב התשאול של ההרצה.",
|
|
2965
2986
|
"github_pat_classic_account_wide": "זהו אסימון קלאסי עם ההרשאה 'repo': הוא מגיע לכל מאגר שאתם יכולים לדחוף אליו, כולל מאגרים שאפליקציית GitHub של סביבת העבודה הזו מעולם לא הותקנה בהם. הרצות שאתם מתחילים משתמשות בו במקום באפליקציה. אסימון מפורט המוגבל למאגרים של התקנה זו צר יותר.",
|
|
2966
2987
|
"github_pat_scopes_beyond_need": "האסימון הזה מעניק הרשאות ש-cat-factory לעולם אינה משתמשת בהן. הסרתן אינה עולה דבר ומצמצמת את מה שהרצה שנפרצה יכולה להגיע אליו.",
|
|
2967
|
-
"github_pat_scope_unreadable": "GitHub קיבלה את האסימון הזה אך לא דיווחה על ההרשאות שלו, ולכן לא ניתן להציג כאן את טווחו. בדקו בהגדרות האסימונים שלכם ב-GitHub מה הוא מעניק."
|
|
2988
|
+
"github_pat_scope_unreadable": "GitHub קיבלה את האסימון הזה אך לא דיווחה על ההרשאות שלו, ולכן לא ניתן להציג כאן את טווחו. בדקו בהגדרות האסימונים שלכם ב-GitHub מה הוא מעניק.",
|
|
2989
|
+
"github_pat_no_scopes": "GitHub אינו מדווח על היקפי הרשאה לאסימון הקלאסי הזה, ולכן הוא יכול לקרוא רק נתונים ציבוריים. הרצות שמשכפלות, דוחפות או פותחות בקשת משיכה איתו ייכשלו. צור אסימון חדש עם 'repo' ו-'workflow' מסומנים."
|
|
2968
2990
|
}
|
|
2969
2991
|
},
|
|
2970
2992
|
"toast": {
|
package/i18n/locales/it.json
CHANGED
|
@@ -388,7 +388,8 @@
|
|
|
388
388
|
"runner_manifest_no_status_path": "Nessun percorso di stato: ogni polling viene letto come ancora in corso, quindi un job può terminare solo esaurendo il budget di polling dell'esecuzione.",
|
|
389
389
|
"github_pat_classic_account_wide": "È un token classico con l'ambito 'repo': raggiunge ogni repository su cui puoi fare push, compresi quelli in cui l'App GitHub di questo spazio di lavoro non è mai stata installata. Le esecuzioni che avvii lo usano di preferenza rispetto all'App. Un token granulare limitato ai repository di questa installazione è più ristretto.",
|
|
390
390
|
"github_pat_scopes_beyond_need": "Questo token concede permessi che cat-factory non usa mai. Rimuoverli non costa nulla e restringe ciò che un'esecuzione compromessa potrebbe raggiungere.",
|
|
391
|
-
"github_pat_scope_unreadable": "GitHub ha accettato questo token ma non ne ha segnalato gli ambiti, quindi la sua portata non può essere mostrata qui. Verifica cosa concede nelle impostazioni dei token di GitHub."
|
|
391
|
+
"github_pat_scope_unreadable": "GitHub ha accettato questo token ma non ne ha segnalato gli ambiti, quindi la sua portata non può essere mostrata qui. Verifica cosa concede nelle impostazioni dei token di GitHub.",
|
|
392
|
+
"github_pat_no_scopes": "GitHub non riporta alcun ambito per questo token classico, quindi può solo leggere dati pubblici. Le esecuzioni che clonano, inviano commit o aprono una pull request con esso falliranno. Generane uno nuovo con 'repo' e 'workflow' selezionati."
|
|
392
393
|
}
|
|
393
394
|
},
|
|
394
395
|
"toast": {
|
|
@@ -2453,6 +2454,27 @@
|
|
|
2453
2454
|
"createToken": "Crea un token GitHub (scope pre-selezionati)",
|
|
2454
2455
|
"thenSet": "Poi imposta {envVar} e riavvia."
|
|
2455
2456
|
},
|
|
2457
|
+
"githubPatPermissionsBanner": {
|
|
2458
|
+
"title": "Il token GitHub non può fare push né aprire pull request",
|
|
2459
|
+
"rejectedTitle": "GitHub ha rifiutato il token usato dalle tue esecuzioni",
|
|
2460
|
+
"body": "Le esecuzioni avviate qui si autenticano con un personal access token GitHub, e a questo mancano permessi necessari alla pipeline. Le fasi degli agenti che effettuano push di un branch, aprono una pull request o uniscono falliranno.",
|
|
2461
|
+
"rejectedBody": "Il personal access token GitHub con cui si autenticano le tue esecuzioni non è valido, è scaduto, è stato revocato o è bloccato da una policy dell'organizzazione. Ogni fase che clona, effettua push, apre una pull request o unisce fallirà finché non lo sostituisci.",
|
|
2462
|
+
"missing": "Manca:",
|
|
2463
|
+
"alsoMissing": "Manca anche, sebbene blocchi solo le modifiche ai file di workflow: {capabilities}.",
|
|
2464
|
+
"capability": {
|
|
2465
|
+
"push": "effettuare push dei commit",
|
|
2466
|
+
"pullRequests": "aprire e unire pull request",
|
|
2467
|
+
"workflows": "modificare i file di workflow"
|
|
2468
|
+
},
|
|
2469
|
+
"sourceDeployment": "Questo è il token con cui è configurato questo deployment, quindi sostituirlo significa aggiornare il deployment.",
|
|
2470
|
+
"sourceInitiator": "Questo è il tuo token memorizzato, che le tue esecuzioni usano al posto delle credenziali del deployment. Sostituiscilo nelle tue impostazioni personali.",
|
|
2471
|
+
"createClassic": "Crea un token sostitutivo (scope pre-selezionati)",
|
|
2472
|
+
"createFineGrained": "Crea un token sostitutivo fine-grained",
|
|
2473
|
+
"classicHint": "Il link apre il modulo del token classico con gli scope richiesti già selezionati.",
|
|
2474
|
+
"fineGrainedHint": "Il modulo fine-grained di GitHub non accetta pre-selezioni, quindi concedi tu stesso questi permessi di repository: {permissions}.",
|
|
2475
|
+
"sampled": "Verificato su {checked} repository in uso; altri {remaining} non sono stati verificati.",
|
|
2476
|
+
"deniedRepos": "Il token non raggiunge questi repository usati dai tuoi servizi: {repos}. Rigeneralo selezionando quei repository."
|
|
2477
|
+
},
|
|
2456
2478
|
"providerConfigBanner": {
|
|
2457
2479
|
"titleMany": "I provider necessitano di configurazione",
|
|
2458
2480
|
"titleOne": {
|
package/i18n/locales/ja.json
CHANGED
|
@@ -2234,6 +2234,27 @@
|
|
|
2234
2234
|
"createToken": "GitHub トークンを作成(スコープは事前選択済み)",
|
|
2235
2235
|
"thenSet": "その後 {envVar} を設定して再起動してください。"
|
|
2236
2236
|
},
|
|
2237
|
+
"githubPatPermissionsBanner": {
|
|
2238
|
+
"title": "GitHub トークンにプッシュやプルリクエスト作成の権限がありません",
|
|
2239
|
+
"rejectedTitle": "GitHub が実行で使うトークンを拒否しました",
|
|
2240
|
+
"body": "ここで開始した実行は GitHub の個人アクセストークンで認証しますが、このトークンにはパイプラインに必要な権限がありません。ブランチのプッシュ、プルリクエストの作成、マージを行うエージェントステップは失敗します。",
|
|
2241
|
+
"rejectedBody": "実行の認証に使う GitHub 個人アクセストークンが、無効・期限切れ・失効、または組織ポリシーによりブロックされています。置き換えるまで、クローン、プッシュ、プルリクエスト作成、マージを行うすべてのステップが失敗します。",
|
|
2242
|
+
"missing": "不足:",
|
|
2243
|
+
"alsoMissing": "ワークフローファイルの変更のみを妨げるものですが、次も不足しています: {capabilities}。",
|
|
2244
|
+
"capability": {
|
|
2245
|
+
"push": "コミットのプッシュ",
|
|
2246
|
+
"pullRequests": "プルリクエストの作成とマージ",
|
|
2247
|
+
"workflows": "ワークフローファイルの編集"
|
|
2248
|
+
},
|
|
2249
|
+
"sourceDeployment": "これはこのデプロイに設定されているトークンです。置き換えるにはデプロイの更新が必要です。",
|
|
2250
|
+
"sourceInitiator": "これはあなた自身の保存済みトークンで、実行はデプロイの資格情報よりこちらを優先します。個人設定で置き換えてください。",
|
|
2251
|
+
"createClassic": "置き換え用トークンを作成(スコープは事前選択済み)",
|
|
2252
|
+
"createFineGrained": "置き換え用のきめ細かいトークンを作成",
|
|
2253
|
+
"classicHint": "リンクを開くと、必要なスコープが選択済みのクラシックトークン作成フォームが表示されます。",
|
|
2254
|
+
"fineGrainedHint": "GitHub のきめ細かいトークンのフォームは事前選択に対応していないため、次のリポジトリ権限をご自身で付与してください: {permissions}。",
|
|
2255
|
+
"sampled": "使用中のリポジトリ {checked} 件を確認しました。残り {remaining} 件は未確認です。",
|
|
2256
|
+
"deniedRepos": "このトークンはサービスが使用する次のリポジトリにアクセスできません: {repos}。これらのリポジトリを選択して再発行してください。"
|
|
2257
|
+
},
|
|
2237
2258
|
"providerConfigBanner": {
|
|
2238
2259
|
"titleMany": "プロバイダーの設定が必要です",
|
|
2239
2260
|
"titleOne": {
|
|
@@ -2964,7 +2985,8 @@
|
|
|
2964
2985
|
"runner_manifest_no_status_path": "ステータスパスがありません。ポーリングは常に実行中と解釈されるため、ジョブは実行のポーリング上限を使い切ることでしか終了できません。",
|
|
2965
2986
|
"github_pat_classic_account_wide": "これは 'repo' スコープを持つクラシックトークンです。あなたがプッシュできるすべてのリポジトリ(このワークスペースの GitHub App が一度もインストールされていないものを含む)に到達します。あなたが開始する実行は App よりこれを優先して使います。このインストールのリポジトリに限定したファイングレインドトークンのほうが範囲は狭くなります。",
|
|
2966
2987
|
"github_pat_scopes_beyond_need": "このトークンは cat-factory が使わない権限を含んでいます。外しても支障はなく、侵害された実行が到達できる範囲を狭められます。",
|
|
2967
|
-
"github_pat_scope_unreadable": "GitHub はこのトークンを受け入れましたが、スコープを報告しなかったため、ここでは到達範囲を表示できません。GitHub のトークン設定で何が付与されているか確認してください。"
|
|
2988
|
+
"github_pat_scope_unreadable": "GitHub はこのトークンを受け入れましたが、スコープを報告しなかったため、ここでは到達範囲を表示できません。GitHub のトークン設定で何が付与されているか確認してください。",
|
|
2989
|
+
"github_pat_no_scopes": "GitHub はこのクラシックトークンのスコープを報告していないため、公開データの読み取りしかできません。これを使ってクローン、プッシュ、プルリクエストの作成を行う実行は失敗します。'repo' と 'workflow' を選択して新しいトークンを発行してください。"
|
|
2968
2990
|
}
|
|
2969
2991
|
},
|
|
2970
2992
|
"toast": {
|
package/i18n/locales/pl.json
CHANGED
|
@@ -2234,6 +2234,27 @@
|
|
|
2234
2234
|
"createToken": "Utwórz token GitHub (zakresy wstępnie wybrane)",
|
|
2235
2235
|
"thenSet": "Następnie ustaw {envVar} i uruchom ponownie."
|
|
2236
2236
|
},
|
|
2237
|
+
"githubPatPermissionsBanner": {
|
|
2238
|
+
"title": "Token GitHub nie może wypychać zmian ani otwierać pull requestów",
|
|
2239
|
+
"rejectedTitle": "GitHub odrzucił token używany przez Twoje uruchomienia",
|
|
2240
|
+
"body": "Uruchomienia rozpoczęte tutaj uwierzytelniają się osobistym tokenem dostępu GitHub, a temu brakuje uprawnień wymaganych przez potok. Kroki agenta, które wypychają gałąź, otwierają pull request lub scalają, zakończą się niepowodzeniem.",
|
|
2241
|
+
"rejectedBody": "Osobisty token dostępu GitHub, którym uwierzytelniają się Twoje uruchomienia, jest nieprawidłowy, wygasł, został unieważniony lub zablokowany przez zasady organizacji. Każdy krok, który klonuje, wypycha, otwiera pull request lub scala, będzie kończył się niepowodzeniem, dopóki go nie wymienisz.",
|
|
2242
|
+
"missing": "Brakuje:",
|
|
2243
|
+
"alsoMissing": "Brakuje również, choć blokuje to tylko zmiany w plikach przepływów pracy: {capabilities}.",
|
|
2244
|
+
"capability": {
|
|
2245
|
+
"push": "wypychanie commitów",
|
|
2246
|
+
"pullRequests": "otwieranie i scalanie pull requestów",
|
|
2247
|
+
"workflows": "edytowanie plików przepływów pracy"
|
|
2248
|
+
},
|
|
2249
|
+
"sourceDeployment": "To jest token skonfigurowany dla tego wdrożenia, więc jego wymiana oznacza aktualizację wdrożenia.",
|
|
2250
|
+
"sourceInitiator": "To Twój własny zapisany token, którego Twoje uruchomienia używają zamiast poświadczeń wdrożenia. Wymień go w swoich ustawieniach osobistych.",
|
|
2251
|
+
"createClassic": "Utwórz token zastępczy (zakresy wstępnie wybrane)",
|
|
2252
|
+
"createFineGrained": "Utwórz zastępczy token o precyzyjnych uprawnieniach",
|
|
2253
|
+
"classicHint": "Link otwiera formularz klasycznego tokenu z już zaznaczonymi wymaganymi zakresami.",
|
|
2254
|
+
"fineGrainedHint": "Formularz precyzyjnych uprawnień GitHub nie obsługuje wstępnego wyboru, więc nadaj te uprawnienia repozytorium samodzielnie: {permissions}.",
|
|
2255
|
+
"sampled": "Sprawdzono {checked} używanych repozytoriów; kolejnych {remaining} nie sprawdzono.",
|
|
2256
|
+
"deniedRepos": "Token nie ma dostępu do tych repozytoriów używanych przez Twoje usługi: {repos}. Wygeneruj go ponownie z zaznaczonymi tymi repozytoriami."
|
|
2257
|
+
},
|
|
2237
2258
|
"providerConfigBanner": {
|
|
2238
2259
|
"titleMany": "Dostawcy wymagają konfiguracji",
|
|
2239
2260
|
"titleOne": {
|
|
@@ -2763,7 +2784,8 @@
|
|
|
2763
2784
|
"runner_manifest_no_status_path": "Brak ścieżki statusu: każde odpytanie jest odczytywane jako wciąż trwające, więc zadanie może zakończyć się tylko po wyczerpaniu budżetu odpytań przebiegu.",
|
|
2764
2785
|
"github_pat_classic_account_wide": "To klasyczny token z zakresem 'repo': sięga każdego repozytorium, do którego możesz wypychać zmiany, także tych, w których aplikacja GitHub tego obszaru roboczego nigdy nie została zainstalowana. Uruchomienia, które rozpoczynasz, używają go zamiast aplikacji. Token szczegółowy ograniczony do repozytoriów tej instalacji jest węższy.",
|
|
2765
2786
|
"github_pat_scopes_beyond_need": "Ten token przyznaje uprawnienia, z których cat-factory nigdy nie korzysta. Ich usunięcie nic nie kosztuje i zawęża to, co mogłoby osiągnąć skompromitowane uruchomienie.",
|
|
2766
|
-
"github_pat_scope_unreadable": "GitHub przyjął ten token, ale nie zgłosił jego zakresów, więc jego zasięgu nie da się tu pokazać. Sprawdź w ustawieniach tokenów GitHub, co przyznaje."
|
|
2787
|
+
"github_pat_scope_unreadable": "GitHub przyjął ten token, ale nie zgłosił jego zakresów, więc jego zasięgu nie da się tu pokazać. Sprawdź w ustawieniach tokenów GitHub, co przyznaje.",
|
|
2788
|
+
"github_pat_no_scopes": "GitHub nie zgłasza żadnych zakresów dla tego klasycznego tokena, więc może on tylko odczytywać dane publiczne. Uruchomienia, które klonują, wypychają zmiany lub otwierają pull requesta przy jego użyciu, zakończą się niepowodzeniem. Wygeneruj nowy z zaznaczonymi 'repo' i 'workflow'."
|
|
2767
2789
|
}
|
|
2768
2790
|
},
|
|
2769
2791
|
"toast": {
|
package/i18n/locales/tr.json
CHANGED
|
@@ -2234,6 +2234,27 @@
|
|
|
2234
2234
|
"createToken": "GitHub belirteci oluştur (kapsamlar önceden seçili)",
|
|
2235
2235
|
"thenSet": "Ardından {envVar} ayarlayın ve yeniden başlatın."
|
|
2236
2236
|
},
|
|
2237
|
+
"githubPatPermissionsBanner": {
|
|
2238
|
+
"title": "GitHub belirteci push yapamıyor veya pull request açamıyor",
|
|
2239
|
+
"rejectedTitle": "GitHub, çalıştırmalarınızın kullandığı belirteci reddetti",
|
|
2240
|
+
"body": "Burada başlatılan çalıştırmalar bir GitHub kişisel erişim belirteciyle kimlik doğrular ve bu belirteçte iş hattının ihtiyaç duyduğu izinler yok. Dal push eden, pull request açan veya birleştiren ajan adımları başarısız olacak.",
|
|
2241
|
+
"rejectedBody": "Çalıştırmalarınızın kimlik doğruladığı GitHub kişisel erişim belirteci geçersiz, süresi dolmuş, iptal edilmiş ya da bir kuruluş politikası tarafından engellenmiş. Değiştirilene kadar klonlayan, push eden, pull request açan veya birleştiren her adım başarısız olacak.",
|
|
2242
|
+
"missing": "Eksik:",
|
|
2243
|
+
"alsoMissing": "Yalnızca iş akışı dosyalarındaki değişiklikleri engellese de şu da eksik: {capabilities}.",
|
|
2244
|
+
"capability": {
|
|
2245
|
+
"push": "commit push etme",
|
|
2246
|
+
"pullRequests": "pull request açma ve birleştirme",
|
|
2247
|
+
"workflows": "iş akışı dosyalarını düzenleme"
|
|
2248
|
+
},
|
|
2249
|
+
"sourceDeployment": "Bu, bu dağıtımın yapılandırıldığı belirteçtir; değiştirmek dağıtımı güncellemek anlamına gelir.",
|
|
2250
|
+
"sourceInitiator": "Bu, çalıştırmalarınızın dağıtım kimlik bilgisi yerine tercih ettiği kendi kayıtlı belirtecinizdir. Kişisel ayarlarınızdan değiştirin.",
|
|
2251
|
+
"createClassic": "Yerine belirteç oluştur (kapsamlar önceden seçili)",
|
|
2252
|
+
"createFineGrained": "Yerine ayrıntılı izinli belirteç oluştur",
|
|
2253
|
+
"classicHint": "Bağlantı, gerekli kapsamlar zaten seçili hâlde klasik belirteç formunu açar.",
|
|
2254
|
+
"fineGrainedHint": "GitHub'ın ayrıntılı izin formu ön seçim kabul etmez; bu depo izinlerini kendiniz verin: {permissions}.",
|
|
2255
|
+
"sampled": "Kullanılan {checked} depoya karşı denetlendi; {remaining} tanesi denetlenmedi.",
|
|
2256
|
+
"deniedRepos": "Belirteç, hizmetlerinizin kullandığı şu depolara erişemiyor: {repos}. Bu depoları seçerek yeniden oluşturun."
|
|
2257
|
+
},
|
|
2237
2258
|
"providerConfigBanner": {
|
|
2238
2259
|
"titleMany": "Sağlayıcıların yapılandırılması gerekiyor",
|
|
2239
2260
|
"titleOne": {
|
|
@@ -2964,7 +2985,8 @@
|
|
|
2964
2985
|
"runner_manifest_no_status_path": "Durum yolu yok: her yoklama hâlâ çalışıyor olarak okunur, bu yüzden bir iş ancak çalıştırmanın yoklama bütçesi tükendiğinde sona erebilir.",
|
|
2965
2986
|
"github_pat_classic_account_wide": "Bu, 'repo' kapsamına sahip klasik bir belirteç: gönderim yapabildiğiniz her depoya, bu çalışma alanının GitHub Uygulamasının hiç kurulmadığı depolar dahil, erişir. Başlattığınız çalıştırmalar bunu Uygulamaya tercih eder. Bu kurulumun depolarıyla sınırlı ince ayarlı bir belirteç daha dardır.",
|
|
2966
2987
|
"github_pat_scopes_beyond_need": "Bu belirteç, cat-factory'nin hiç kullanmadığı izinler veriyor. Bunları kaldırmak hiçbir şeye mal olmaz ve ele geçirilmiş bir çalıştırmanın erişebileceği alanı daraltır.",
|
|
2967
|
-
"github_pat_scope_unreadable": "GitHub bu belirteci kabul etti ancak kapsamlarını bildirmedi, bu yüzden erişimi burada gösterilemiyor. Neler verdiğini GitHub belirteç ayarlarınızdan kontrol edin."
|
|
2988
|
+
"github_pat_scope_unreadable": "GitHub bu belirteci kabul etti ancak kapsamlarını bildirmedi, bu yüzden erişimi burada gösterilemiyor. Neler verdiğini GitHub belirteç ayarlarınızdan kontrol edin.",
|
|
2989
|
+
"github_pat_no_scopes": "GitHub bu klasik belirteç için hiçbir kapsam bildirmiyor, dolayısıyla yalnızca herkese açık verileri okuyabilir. Onunla klonlayan, gönderim yapan veya pull request açan çalıştırmalar başarısız olur. 'repo' ve 'workflow' seçili yeni bir belirteç oluşturun."
|
|
2968
2990
|
}
|
|
2969
2991
|
},
|
|
2970
2992
|
"toast": {
|
package/i18n/locales/uk.json
CHANGED
|
@@ -2234,6 +2234,27 @@
|
|
|
2234
2234
|
"createToken": "Створити токен GitHub (області попередньо вибрані)",
|
|
2235
2235
|
"thenSet": "Потім встановіть {envVar} і перезапустіть."
|
|
2236
2236
|
},
|
|
2237
|
+
"githubPatPermissionsBanner": {
|
|
2238
|
+
"title": "Токен GitHub не може надсилати зміни або відкривати pull request-и",
|
|
2239
|
+
"rejectedTitle": "GitHub відхилив токен, який використовують ваші запуски",
|
|
2240
|
+
"body": "Запуски, розпочаті тут, автентифікуються особистим токеном доступу GitHub, і цьому бракує дозволів, потрібних конвеєру. Кроки агента, які надсилають гілку, відкривають pull request або зливають, завершаться невдало.",
|
|
2241
|
+
"rejectedBody": "Особистий токен доступу GitHub, яким автентифікуються ваші запуски, недійсний, прострочений, відкликаний або заблокований політикою організації. Кожен крок, який клонує, надсилає, відкриває pull request чи зливає, завершуватиметься невдало, доки ви його не заміните.",
|
|
2242
|
+
"missing": "Бракує:",
|
|
2243
|
+
"alsoMissing": "Також бракує, хоча це блокує лише зміни у файлах робочих процесів: {capabilities}.",
|
|
2244
|
+
"capability": {
|
|
2245
|
+
"push": "надсилання комітів",
|
|
2246
|
+
"pullRequests": "відкриття та злиття pull request-ів",
|
|
2247
|
+
"workflows": "редагування файлів робочих процесів"
|
|
2248
|
+
},
|
|
2249
|
+
"sourceDeployment": "Це токен, з яким налаштовано це розгортання, тож його заміна означає оновлення розгортання.",
|
|
2250
|
+
"sourceInitiator": "Це ваш власний збережений токен, який ваші запуски використовують замість облікових даних розгортання. Замініть його в особистих налаштуваннях.",
|
|
2251
|
+
"createClassic": "Створити токен на заміну (області попередньо вибрані)",
|
|
2252
|
+
"createFineGrained": "Створити токен на заміну з точними дозволами",
|
|
2253
|
+
"classicHint": "Посилання відкриває форму класичного токена з уже вибраними потрібними областями.",
|
|
2254
|
+
"fineGrainedHint": "Форма точних дозволів GitHub не підтримує попередній вибір, тож надайте ці дозволи репозиторію самостійно: {permissions}.",
|
|
2255
|
+
"sampled": "Перевірено {checked} використовуваних репозиторіїв; ще {remaining} не перевірено.",
|
|
2256
|
+
"deniedRepos": "Токен не має доступу до цих репозиторіїв, які використовують ваші сервіси: {repos}. Створіть його заново, обравши ці репозиторії."
|
|
2257
|
+
},
|
|
2237
2258
|
"providerConfigBanner": {
|
|
2238
2259
|
"titleMany": "Постачальники потребують налаштування",
|
|
2239
2260
|
"titleOne": {
|
|
@@ -2763,7 +2784,8 @@
|
|
|
2763
2784
|
"runner_manifest_no_status_path": "Немає шляху до статусу: кожне опитування читається як таке, що ще триває, тож завдання може завершитися лише після вичерпання бюджету опитувань запуску.",
|
|
2764
2785
|
"github_pat_classic_account_wide": "Це класичний токен з областю 'repo': він сягає кожного репозиторію, до якого ви можете надсилати зміни, зокрема тих, де застосунок GitHub цього робочого простору ніколи не встановлювався. Запуски, які ви розпочинаєте, використовують його замість застосунку. Деталізований токен, обмежений репозиторіями цього встановлення, вужчий.",
|
|
2765
2786
|
"github_pat_scopes_beyond_need": "Цей токен надає дозволи, якими cat-factory ніколи не користується. Прибрати їх нічого не коштує, і це звужує те, чого міг би сягнути скомпрометований запуск.",
|
|
2766
|
-
"github_pat_scope_unreadable": "GitHub прийняв цей токен, але не повідомив його областей, тож показати його обсяг доступу тут неможливо. Перевірте в налаштуваннях токенів GitHub, що саме він надає."
|
|
2787
|
+
"github_pat_scope_unreadable": "GitHub прийняв цей токен, але не повідомив його областей, тож показати його обсяг доступу тут неможливо. Перевірте в налаштуваннях токенів GitHub, що саме він надає.",
|
|
2788
|
+
"github_pat_no_scopes": "GitHub не повідомляє жодних областей дії для цього класичного токена, тож він може лише читати публічні дані. Запуски, які клонують, надсилають зміни або відкривають pull request із ним, завершаться помилкою. Створіть новий із вибраними 'repo' і 'workflow'."
|
|
2767
2789
|
}
|
|
2768
2790
|
},
|
|
2769
2791
|
"toast": {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cat-factory/app",
|
|
3
|
-
"version": "0.261.
|
|
3
|
+
"version": "0.261.2",
|
|
4
4
|
"description": "Reusable Nuxt layer for the Agent Architecture Board SPA (components, stores, composables, pages). Consume it from a thin deployment app via `extends: ['@cat-factory/app']` and point it at your backend with NUXT_PUBLIC_API_BASE. See deploy/frontend for an example.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"valibot": "^1.4.2",
|
|
41
41
|
"vue": "3.5.41",
|
|
42
42
|
"wretch": "^3.0.9",
|
|
43
|
-
"@cat-factory/contracts": "0.292.
|
|
43
|
+
"@cat-factory/contracts": "0.292.2"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"@toad-contracts/testing": "0.3.2",
|