Skip to content

Commit 24ec4d4

Browse files
committed
refactor: migrate to zod v4
1 parent 0032f67 commit 24ec4d4

File tree

12 files changed

+5705
-6635
lines changed

12 files changed

+5705
-6635
lines changed

action/dist/main/index.js

Lines changed: 5639 additions & 6542 deletions
Large diffs are not rendered by default.

action/package-lock.json

Lines changed: 5 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

action/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
"@smithy/signature-v4": "^5.1.1",
1919
"ts-node": "^10.9.2",
2020
"yaml": "^2.8.0",
21-
"zod": "^3.25.75"
21+
"zod": "^4.0.5"
2222
},
2323
"devDependencies": {
2424
"@eslint/eslintrc": "^3.3.1",

action/src/action-main.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ runAction(async () => {
1616
const input = {
1717
scope: z.enum(['repos', 'owner'])
1818
.parse(getInput('scope')),
19-
permissions: z.record(z.string())
19+
permissions: z.record(z.string(), z.string())
2020
.parse(getYamlInput('permissions', {required: true})),
2121
repository: getInput('repository'),
2222
repositories: z.array(z.string()).default([])

server/package-lock.json

Lines changed: 5 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

server/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
"hono": "^4.8.5",
2323
"pino": "^9.7.0",
2424
"yaml": "^2.8.0",
25-
"zod": "^3.25.75"
25+
"zod": "^4.0.5"
2626
},
2727
"devDependencies": {
2828
"@cloudflare/workers-types": "^4.20250712.0",

server/playground.ts

Whitespace-only changes.

server/src/access-token-manager.ts

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -116,11 +116,6 @@ export async function accessTokenManager(options: {
116116
}
117117
}
118118

119-
const appInstallationClient = await createOctokit(GITHUB_APP_CLIENT, appInstallation, {
120-
// single_file to read access policy files
121-
permissions: {single_file: 'read'},
122-
});
123-
124119
// === verify requested token permissions against app installation permissions =====================================
125120
{
126121
const requestedAppInstallationPermissions = verifyPermissions({
@@ -144,6 +139,11 @@ export async function accessTokenManager(options: {
144139
}
145140
}
146141

142+
const appInstallationClient = await createOctokit(GITHUB_APP_CLIENT, appInstallation, {
143+
// single_file to read access policy files
144+
permissions: {single_file: 'read'},
145+
});
146+
147147
// --- load owner access policy ----------------------------------------------------------------------------------
148148
const ownerAccessPolicy = await getOwnerAccessPolicy(appInstallationClient, {
149149
owner: tokenRequest.owner,
@@ -584,7 +584,7 @@ async function getAccessPolicy<T extends typeof GitHubAccessPolicySchema>(client
584584
const issues = policyParseResult.error.issues.map(formatZodIssue);
585585
throw new GithubAccessPolicyError(`Invalid access policy`, issues);
586586
}
587-
const policy: GitHubAccessPolicy = policyParseResult.data;
587+
const policy = policyParseResult.data;
588588

589589
const expectedPolicyOrigin = `${owner}/${repo}`;
590590
if (policy.origin.toLowerCase() !== expectedPolicyOrigin.toLowerCase()) {
@@ -1035,31 +1035,35 @@ const GitHubBaseStatementSchema = z.strictObject({
10351035
subjects: z.array(GitHubSubjectClaimSchema),
10361036
});
10371037

1038-
const GitHubAccessStatementSchema = GitHubBaseStatementSchema.merge(z.strictObject({
1038+
const GitHubAccessStatementSchema = z.strictObject({
1039+
...GitHubBaseStatementSchema.shape,
10391040
permissions: GitHubAppPermissionsSchema,
1040-
}));
1041+
});
10411042
type GitHubAccessStatement = z.infer<typeof GitHubAccessStatementSchema>;
10421043

1043-
const GitHubRepositoryAccessStatementSchema = GitHubBaseStatementSchema.merge(z.strictObject({
1044+
const GitHubRepositoryAccessStatementSchema = z.strictObject({
1045+
...GitHubBaseStatementSchema.shape,
10441046
permissions: GitHubAppRepositoryPermissionsSchema,
1045-
}));
1047+
});
10461048
export type GitHubRepositoryAccessStatement = z.infer<typeof GitHubRepositoryAccessStatementSchema>;
10471049

10481050
const GitHubAccessPolicySchema = z.strictObject({
10491051
origin: GitHubRepositorySchema,
10501052
});
10511053
export type GitHubAccessPolicy = z.infer<typeof GitHubAccessPolicySchema>;
10521054

1053-
const GitHubOwnerAccessPolicySchema = GitHubAccessPolicySchema.merge(z.strictObject({
1055+
const GitHubOwnerAccessPolicySchema = z.strictObject({
1056+
...GitHubAccessPolicySchema.shape,
10541057
'allowed-subjects': z.array(GitHubSubjectClaimSchema).optional(),
10551058
'statements': z.array(GitHubAccessStatementSchema).optional().default([]),
10561059
'allowed-repository-permissions': GitHubAppRepositoryPermissionsSchema.optional().default({}),
1057-
}));
1060+
});
10581061
export type GitHubOwnerAccessPolicy = z.infer<typeof GitHubOwnerAccessPolicySchema>;
10591062

1060-
const GitHubRepositoryAccessPolicySchema = GitHubAccessPolicySchema.merge(z.strictObject({
1063+
const GitHubRepositoryAccessPolicySchema = z.strictObject({
1064+
...GitHubAccessPolicySchema.shape,
10611065
statements: z.array(GitHubRepositoryAccessStatementSchema).optional().default([]),
1062-
}));
1066+
});
10631067
export type GitHubRepositoryAccessPolicy = z.infer<typeof GitHubRepositoryAccessPolicySchema>;
10641068

10651069

server/src/app.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,10 @@ const AccessTokenRequestBodySchema = z.strictObject({
188188
owner: GitHubRepositoryOwnerSchema.optional(),
189189
scope: z.enum(['repos', 'owner']).default('repos'),
190190
permissions: GitHubAppPermissionsSchema,
191-
repositories: z.array(z.union([GitHubRepositoryNameSchema, GitHubRepositorySchema])).default([]),
191+
repositories: z.array(z.union([
192+
GitHubRepositoryNameSchema,
193+
GitHubRepositorySchema,
194+
], {error: `Invalid repository`}),
195+
).default([]),
192196
});
193197
type AccessTokenRequestBody = z.infer<typeof AccessTokenRequestBodySchema>;

server/src/common/github-utils.ts

Lines changed: 14 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import {components} from '@octokit/openapi-types';
22
import {z} from 'zod';
33
import {mapObjectEntries, tuplesOf} from './common-utils.js';
4-
import {zStringRegex} from './zod-utils.js';
54

65
// --- Functions -------------------------------------------------------------------------------------------------------
76

@@ -150,16 +149,16 @@ export function buildWorkflowRunUrl(token: GitHubActionsJwtPayload) {
150149
// --- Schemas ---------------------------------------------------------------------------------------------------------
151150

152151
const GitHubRepositoryOwnerRegex = /^[a-z\d](-?[a-z\d])+$/i;
153-
export const GitHubRepositoryOwnerSchema = zStringRegex(GitHubRepositoryOwnerRegex);
152+
export const GitHubRepositoryOwnerSchema = z.string().regex(GitHubRepositoryOwnerRegex);
154153
const GitHubRepositoryNameRegex = /^[a-z\d-._]+$/i;
155-
export const GitHubRepositoryNameSchema = zStringRegex(GitHubRepositoryNameRegex);
154+
export const GitHubRepositoryNameSchema = z.string().regex(GitHubRepositoryNameRegex);
156155

157-
export const GitHubRepositorySchema = zStringRegex(
156+
export const GitHubRepositorySchema = z.string().regex(
158157
new RegExp(`^${GitHubRepositoryOwnerRegex.source.replace(/^\^|\$$/g, '')}` +
159158
`/${GitHubRepositoryNameRegex.source.replace(/^\^|\$$/g, '')}$`, 'i'),
160159
);
161160

162-
export const GitHubAppPermissionsSchema = z.strictObject({
161+
export const GitHubAppRepositoryPermissionsSchema = z.strictObject({
163162
// ---- Repository Permissions ----
164163
'actions': z.enum(['read', 'write']),
165164
'actions-variables': z.enum(['read', 'write']),
@@ -193,6 +192,10 @@ export const GitHubAppPermissionsSchema = z.strictObject({
193192
'team-discussions': z.enum(['read', 'write']),
194193
'vulnerability-alerts': z.enum(['read', 'write']),
195194
'workflows': z.enum(['write']),
195+
}).partial();
196+
export type GitHubAppRepositoryPermissions = z.infer<typeof GitHubAppRepositoryPermissionsSchema>;
197+
198+
export const GitHubAppOrganizationPermissionsSchema = z.strictObject({
196199
// ---- Organization Permissions ----
197200
'members': z.enum(['read', 'write']),
198201
'organization-actions-variables': z.enum(['read', 'write']),
@@ -216,49 +219,13 @@ export const GitHubAppPermissionsSchema = z.strictObject({
216219
'organization-self-hosted-runners': z.enum(['read', 'write']),
217220
'organization-user-blocking': z.enum(['read', 'write']),
218221
}).partial();
219-
export type GitHubAppPermissions = z.infer<typeof GitHubAppPermissionsSchema>;
222+
export type GitHubAppOrganizationPermissions = z.infer<typeof GitHubAppOrganizationPermissionsSchema>;
220223

221-
/**
222-
* === BE AWARE ===
223-
* - 'administration' scope can not be completely limited to a repository e.g. create new repositories is still possible
224-
* - repository scopes do not start with 'organization-'
225-
* - 'member' scope is an organization scope
226-
*/
227-
export const GitHubAppRepositoryPermissionsSchema = GitHubAppPermissionsSchema.pick({
228-
'actions': true,
229-
'actions-variables': true,
230-
'administration': true,
231-
'checks': true,
232-
'codespaces': true,
233-
'codespaces-lifecycle-admin': true,
234-
'codespaces-metadata': true,
235-
'codespaces-secrets': true,
236-
'contents': true,
237-
'custom-properties': true,
238-
'dependabot-secrets': true,
239-
'deployments': true,
240-
'discussions': true,
241-
'environments': true,
242-
'issues': true,
243-
'merge-queues': true,
244-
'metadata': true,
245-
'packages': true,
246-
'pages': true,
247-
'projects': true,
248-
'pull-requests': true,
249-
'repository-advisories': true,
250-
'repository-hooks': true,
251-
'repository-projects': true,
252-
'secret-scanning-alerts': true,
253-
'secrets': true,
254-
'security-events': true,
255-
'single-file': true,
256-
'statuses': true,
257-
'team-discussions': true,
258-
'vulnerability-alerts': true,
259-
'workflows': true,
260-
});
261-
export type GitHubAppRepositoryPermissions = z.infer<typeof GitHubAppRepositoryPermissionsSchema>;
224+
export const GitHubAppPermissionsSchema = z.strictObject({
225+
...GitHubAppRepositoryPermissionsSchema.shape,
226+
...GitHubAppOrganizationPermissionsSchema.shape,
227+
}).partial();
228+
export type GitHubAppPermissions = z.infer<typeof GitHubAppPermissionsSchema>;
262229

263230
// --- Types -----------------------------------------------------------------------------------------------------------
264231

0 commit comments

Comments
 (0)