mirror of
https://github.com/kunkunsh/kunkun.git
synced 2025-04-04 14:46:42 +00:00
feat: add repo ownership check for org in jsr validation algo
This commit is contained in:
parent
0af6ef2d0a
commit
f6b70bade0
@ -43,6 +43,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@huakunshen/jsr-client": "^0.1.5",
|
||||
"@octokit/rest": "^21.1.0",
|
||||
"@tauri-apps/api": "^2.2.0",
|
||||
"@tauri-apps/cli": "^2.2.2",
|
||||
"@tauri-apps/plugin-deep-link": "^2.2.0",
|
||||
|
@ -1,71 +1,75 @@
|
||||
import { describe, expect, test } from "bun:test";
|
||||
import { validateJsrPackageAsKunkunExtension } from "../index";
|
||||
import { describe, expect, test } from "bun:test"
|
||||
import { validateJsrPackageAsKunkunExtension } from "../index"
|
||||
|
||||
describe("Validate Jsr package as Kunkun extension", () => {
|
||||
test("Package not signed by GitHub Actions", async () => {
|
||||
expect(
|
||||
(await validateJsrPackageAsKunkunExtension({
|
||||
jsrPackage: {
|
||||
scope: "kunkun",
|
||||
name: "api",
|
||||
version: "0.0.47",
|
||||
},
|
||||
githubUsername: "kunkunsh",
|
||||
})).error,
|
||||
).toBe("JSR package is not signed by GitHub Actions");
|
||||
});
|
||||
(
|
||||
await validateJsrPackageAsKunkunExtension({
|
||||
jsrPackage: {
|
||||
scope: "kunkun",
|
||||
name: "api",
|
||||
version: "0.0.47"
|
||||
},
|
||||
githubUsername: "kunkunsh"
|
||||
})
|
||||
).error
|
||||
).toBe("JSR package is not signed by GitHub Actions")
|
||||
})
|
||||
|
||||
test("Non-existent package", async () => {
|
||||
expect(
|
||||
(await validateJsrPackageAsKunkunExtension({
|
||||
jsrPackage: {
|
||||
scope: "kunkun",
|
||||
name: "non-existent-package",
|
||||
version: "0.0.47",
|
||||
},
|
||||
githubUsername: "kunkunsh",
|
||||
})).error,
|
||||
).toBe("JSR package does not exist");
|
||||
});
|
||||
(
|
||||
await validateJsrPackageAsKunkunExtension({
|
||||
jsrPackage: {
|
||||
scope: "kunkun",
|
||||
name: "non-existent-package",
|
||||
version: "0.0.47"
|
||||
},
|
||||
githubUsername: "kunkunsh"
|
||||
})
|
||||
).error
|
||||
).toBe("JSR package does not exist")
|
||||
})
|
||||
|
||||
test("Package not linked to a GitHub repository", async () => {
|
||||
expect(
|
||||
(await validateJsrPackageAsKunkunExtension({
|
||||
jsrPackage: {
|
||||
scope: "hk",
|
||||
name: "tauri-plugin-network-api",
|
||||
version: "2.0.3-beta.1",
|
||||
},
|
||||
githubUsername: "kunkunsh",
|
||||
})).error,
|
||||
).toBe("JSR package is not linked to a GitHub repository");
|
||||
});
|
||||
(
|
||||
await validateJsrPackageAsKunkunExtension({
|
||||
jsrPackage: {
|
||||
scope: "hk",
|
||||
name: "tauri-plugin-network-api",
|
||||
version: "2.0.3-beta.1"
|
||||
},
|
||||
githubUsername: "kunkunsh"
|
||||
})
|
||||
).error
|
||||
).toBe("JSR package is not linked to a GitHub repository")
|
||||
})
|
||||
|
||||
test("GitHub repository owner does not match JSR package owner", async () => {
|
||||
expect(
|
||||
(await validateJsrPackageAsKunkunExtension({
|
||||
jsrPackage: {
|
||||
scope: "kunkun",
|
||||
name: "ext-image-processing",
|
||||
version: "0.0.6",
|
||||
},
|
||||
githubUsername: "kunkunsh", // should be HuakunShen
|
||||
})).error,
|
||||
).toBe(
|
||||
"GitHub repository owner does not match JSR package owner: HuakunShen !== kunkunsh",
|
||||
);
|
||||
});
|
||||
const res = await validateJsrPackageAsKunkunExtension({
|
||||
jsrPackage: {
|
||||
scope: "kunkun",
|
||||
name: "ext-image-processing",
|
||||
version: "0.0.6"
|
||||
},
|
||||
githubUsername: "Huakun"
|
||||
})
|
||||
expect(res.error).toBe(
|
||||
"You (Huakun) are not authorized to publish this package. Only kunkunsh or its organization members can publish it."
|
||||
)
|
||||
})
|
||||
|
||||
test("A valid extension package", async () => {
|
||||
expect(
|
||||
(await validateJsrPackageAsKunkunExtension({
|
||||
jsrPackage: {
|
||||
scope: "kunkun",
|
||||
name: "ext-image-processing",
|
||||
version: "0.0.6",
|
||||
},
|
||||
githubUsername: "HuakunShen",
|
||||
})).data,
|
||||
).toBeDefined();
|
||||
});
|
||||
});
|
||||
const res = await await validateJsrPackageAsKunkunExtension({
|
||||
jsrPackage: {
|
||||
scope: "kunkun",
|
||||
name: "ext-image-processing",
|
||||
version: "0.0.6"
|
||||
},
|
||||
githubUsername: "HuakunShen"
|
||||
})
|
||||
expect(res.data).toBeDefined()
|
||||
})
|
||||
})
|
||||
|
34
packages/api/src/extensions/jsr/github.ts
Normal file
34
packages/api/src/extensions/jsr/github.ts
Normal file
@ -0,0 +1,34 @@
|
||||
/**
|
||||
* TODO: move this module to another folder
|
||||
*/
|
||||
import { Octokit } from "@octokit/rest"
|
||||
|
||||
/**
|
||||
* Check if a user is a public member of a GitHub organization
|
||||
* @param orgName - The name of the GitHub organization
|
||||
* @param username - The username of the user
|
||||
* @returns A promise that resolves to a boolean indicating if the user is a public member of the organization
|
||||
*/
|
||||
export function userIsPublicMemberOfGitHubOrg(orgName: string, username: string): Promise<boolean> {
|
||||
const octokit = new Octokit()
|
||||
return octokit.orgs
|
||||
.checkPublicMembershipForUser({ org: orgName, username })
|
||||
.then(() => true)
|
||||
.catch(() => false)
|
||||
}
|
||||
|
||||
/**
|
||||
* Only works if user grants read:org scope with the org when login
|
||||
* @param orgName
|
||||
* @param username
|
||||
* @param githubToken
|
||||
*/
|
||||
export function authenticatedUserIsMemberOfGitHubOrg(
|
||||
orgName: string,
|
||||
githubToken: string
|
||||
): Promise<boolean> {
|
||||
const octokit = new Octokit({ auth: githubToken })
|
||||
return octokit.orgs.listForAuthenticatedUser().then((res) => {
|
||||
return res.data.some((org) => org.login === orgName)
|
||||
})
|
||||
}
|
@ -2,30 +2,31 @@ import {
|
||||
client,
|
||||
getPackage,
|
||||
getPackageVersion,
|
||||
type GitHubRepository,
|
||||
} from "@huakunshen/jsr-client/hey-api-client";
|
||||
import * as v from "valibot";
|
||||
import { ExtPackageJson } from "../../models/manifest";
|
||||
import type { JsrPackageMetadata, NpmPkgMetadata } from "./models";
|
||||
type GitHubRepository
|
||||
} from "@huakunshen/jsr-client/hey-api-client"
|
||||
import * as v from "valibot"
|
||||
import { ExtPackageJson } from "../../models/manifest"
|
||||
import { authenticatedUserIsMemberOfGitHubOrg, userIsPublicMemberOfGitHubOrg } from "./github"
|
||||
import type { JsrPackageMetadata, NpmPkgMetadata } from "./models"
|
||||
|
||||
export * from "./github"
|
||||
|
||||
client.setConfig({
|
||||
baseUrl: "https://api.jsr.io",
|
||||
});
|
||||
baseUrl: "https://api.jsr.io"
|
||||
})
|
||||
|
||||
export function splitRawJsrPkgName(
|
||||
packageName: string,
|
||||
): Promise<{ scope: string; name: string }> {
|
||||
export function splitRawJsrPkgName(packageName: string): Promise<{ scope: string; name: string }> {
|
||||
return new Promise((resolve, reject) => {
|
||||
// write a regex to match the scope and name
|
||||
const regex = /^@([^@]+)\/([^@]+)$/;
|
||||
const match = packageName.match(regex);
|
||||
const regex = /^@([^@]+)\/([^@]+)$/
|
||||
const match = packageName.match(regex)
|
||||
if (!match) {
|
||||
return reject(new Error("Invalid Jsr package name"));
|
||||
return reject(new Error("Invalid Jsr package name"))
|
||||
}
|
||||
const [, rawScope, name] = match;
|
||||
const scope = rawScope.startsWith("@") ? rawScope.slice(1) : rawScope;
|
||||
return resolve({ scope, name });
|
||||
});
|
||||
const [, rawScope, name] = match
|
||||
const scope = rawScope.startsWith("@") ? rawScope.slice(1) : rawScope
|
||||
return resolve({ scope, name })
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
@ -35,8 +36,7 @@ export function splitRawJsrPkgName(
|
||||
* @param name
|
||||
* @returns
|
||||
*/
|
||||
export const translateJsrToNpmPkgName = (scope: string, name: string) =>
|
||||
`${scope}__${name}`;
|
||||
export const translateJsrToNpmPkgName = (scope: string, name: string) => `${scope}__${name}`
|
||||
|
||||
/**
|
||||
/**
|
||||
@ -46,19 +46,13 @@ export const translateJsrToNpmPkgName = (scope: string, name: string) =>
|
||||
* @param version
|
||||
* @returns
|
||||
*/
|
||||
export function getJsrPackageHtml(
|
||||
scope: string,
|
||||
name: string,
|
||||
version?: string,
|
||||
) {
|
||||
const url = `https://jsr.io/@${scope}/${name}${
|
||||
version ? `@${version}` : ""
|
||||
}`;
|
||||
export function getJsrPackageHtml(scope: string, name: string, version?: string) {
|
||||
const url = `https://jsr.io/@${scope}/${name}${version ? `@${version}` : ""}`
|
||||
return fetch(url, {
|
||||
headers: {
|
||||
"sec-fetch-dest": "document",
|
||||
},
|
||||
}).then((res) => res.text());
|
||||
"sec-fetch-dest": "document"
|
||||
}
|
||||
}).then((res) => res.text())
|
||||
}
|
||||
|
||||
/**
|
||||
@ -68,29 +62,29 @@ export function getJsrPackageHtml(
|
||||
export async function isSignedByGitHubAction(
|
||||
scope: string,
|
||||
name: string,
|
||||
version: string,
|
||||
version: string
|
||||
): Promise<boolean> {
|
||||
const pkgVersion = await getPackageVersion({
|
||||
path: {
|
||||
scope,
|
||||
package: name,
|
||||
version,
|
||||
},
|
||||
});
|
||||
return !!pkgVersion.data?.rekorLogId;
|
||||
version
|
||||
}
|
||||
})
|
||||
return !!pkgVersion.data?.rekorLogId
|
||||
}
|
||||
|
||||
export async function getJsrPackageGitHubRepo(
|
||||
scope: string,
|
||||
name: string,
|
||||
name: string
|
||||
): Promise<GitHubRepository | null> {
|
||||
const pkg = await getPackage({
|
||||
path: {
|
||||
scope,
|
||||
package: name,
|
||||
},
|
||||
});
|
||||
return pkg.data?.githubRepository ?? null;
|
||||
package: name
|
||||
}
|
||||
})
|
||||
return pkg.data?.githubRepository ?? null
|
||||
}
|
||||
|
||||
/**
|
||||
@ -102,12 +96,9 @@ export async function getJsrPackageGitHubRepo(
|
||||
* @param name
|
||||
* @returns
|
||||
*/
|
||||
export function getJsrPackageMetadata(
|
||||
scope: string,
|
||||
name: string,
|
||||
): Promise<JsrPackageMetadata> {
|
||||
const url = `https://jsr.io/@${scope}/${name}/meta.json`;
|
||||
return fetch(url).then((res) => res.json());
|
||||
export function getJsrPackageMetadata(scope: string, name: string): Promise<JsrPackageMetadata> {
|
||||
const url = `https://jsr.io/@${scope}/${name}/meta.json`
|
||||
return fetch(url).then((res) => res.json())
|
||||
}
|
||||
|
||||
/**
|
||||
@ -122,12 +113,12 @@ export function getJsrPackageSrcFile(
|
||||
scope: string,
|
||||
name: string,
|
||||
version: string,
|
||||
file: string,
|
||||
file: string
|
||||
): Promise<string | undefined> {
|
||||
const url = `https://jsr.io/@${scope}/${name}/${version}/${file}`;
|
||||
const url = `https://jsr.io/@${scope}/${name}/${version}/${file}`
|
||||
return fetch(url)
|
||||
.then((res) => res.text())
|
||||
.catch(() => undefined);
|
||||
.catch(() => undefined)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -136,15 +127,10 @@ export function getJsrPackageSrcFile(
|
||||
* @param name
|
||||
* @returns
|
||||
*/
|
||||
export function getJsrNpmPkgMetadata(
|
||||
scope: string,
|
||||
name: string,
|
||||
): Promise<NpmPkgMetadata> {
|
||||
export function getJsrNpmPkgMetadata(scope: string, name: string): Promise<NpmPkgMetadata> {
|
||||
// Sample: https://npm.jsr.io/@jsr/kunkun__api
|
||||
const url = `https://npm.jsr.io/@jsr/${
|
||||
translateJsrToNpmPkgName(scope, name)
|
||||
}`;
|
||||
return fetch(url).then((res) => res.json());
|
||||
const url = `https://npm.jsr.io/@jsr/${translateJsrToNpmPkgName(scope, name)}`
|
||||
return fetch(url).then((res) => res.json())
|
||||
}
|
||||
|
||||
/**
|
||||
@ -154,14 +140,10 @@ export function getJsrNpmPkgMetadata(
|
||||
* @param version
|
||||
* @returns
|
||||
*/
|
||||
export function getJsrNpmPackageVersionMetadata(
|
||||
scope: string,
|
||||
name: string,
|
||||
version: string,
|
||||
) {
|
||||
export function getJsrNpmPackageVersionMetadata(scope: string, name: string, version: string) {
|
||||
return getJsrNpmPkgMetadata(scope, name).then((metadata) => {
|
||||
return metadata.versions[version];
|
||||
});
|
||||
return metadata.versions[version]
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
@ -174,16 +156,11 @@ export function getJsrNpmPackageVersionMetadata(
|
||||
export async function getNpmPackageTarballUrl(
|
||||
scope: string,
|
||||
name: string,
|
||||
version: string,
|
||||
version: string
|
||||
): Promise<string | undefined> {
|
||||
const metadata = await getJsrNpmPackageVersionMetadata(
|
||||
scope,
|
||||
name,
|
||||
version,
|
||||
);
|
||||
const tarballUrl: string | undefined = metadata?.dist
|
||||
.tarball;
|
||||
return tarballUrl;
|
||||
const metadata = await getJsrNpmPackageVersionMetadata(scope, name, version)
|
||||
const tarballUrl: string | undefined = metadata?.dist.tarball
|
||||
return tarballUrl
|
||||
}
|
||||
|
||||
/**
|
||||
@ -192,12 +169,9 @@ export async function getNpmPackageTarballUrl(
|
||||
* @param name
|
||||
* @returns
|
||||
*/
|
||||
export async function getAllVersionsOfJsrPackage(
|
||||
scope: string,
|
||||
name: string,
|
||||
): Promise<string[]> {
|
||||
const metadata = await getJsrNpmPkgMetadata(scope, name);
|
||||
return Object.keys(metadata.versions);
|
||||
export async function getAllVersionsOfJsrPackage(scope: string, name: string): Promise<string[]> {
|
||||
const metadata = await getJsrNpmPkgMetadata(scope, name)
|
||||
return Object.keys(metadata.versions)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -206,26 +180,22 @@ export async function getAllVersionsOfJsrPackage(
|
||||
* @param name
|
||||
* @returns
|
||||
*/
|
||||
export function jsrPackageExists(
|
||||
scope: string,
|
||||
name: string,
|
||||
version?: string,
|
||||
): Promise<boolean> {
|
||||
export function jsrPackageExists(scope: string, name: string, version?: string): Promise<boolean> {
|
||||
if (version) {
|
||||
return getPackageVersion({
|
||||
path: {
|
||||
scope,
|
||||
package: name,
|
||||
version,
|
||||
},
|
||||
}).then((res) => res.response.ok && res.response.status === 200);
|
||||
version
|
||||
}
|
||||
}).then((res) => res.response.ok && res.response.status === 200)
|
||||
}
|
||||
return getPackage({
|
||||
path: {
|
||||
scope,
|
||||
package: name,
|
||||
},
|
||||
}).then((res) => res.response.ok && res.response.status === 200);
|
||||
package: name
|
||||
}
|
||||
}).then((res) => res.response.ok && res.response.status === 200)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -236,10 +206,10 @@ export function jsrPackageExists(
|
||||
export function getTarballSize(url: string): Promise<number> {
|
||||
return fetch(url, { method: "HEAD" }).then((res) => {
|
||||
if (!(res.ok && res.status === 200)) {
|
||||
throw new Error("Failed to fetch tarball size");
|
||||
throw new Error("Failed to fetch tarball size")
|
||||
}
|
||||
return Number(res.headers.get("Content-Length"));
|
||||
});
|
||||
return Number(res.headers.get("Content-Length"))
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
@ -254,40 +224,41 @@ export function getTarballSize(url: string): Promise<number> {
|
||||
*/
|
||||
export async function validateJsrPackageAsKunkunExtension(payload: {
|
||||
jsrPackage: {
|
||||
scope: string;
|
||||
name: string;
|
||||
version: string;
|
||||
};
|
||||
githubUsername: string;
|
||||
tarballSizeLimit?: number;
|
||||
scope: string
|
||||
name: string
|
||||
version: string
|
||||
}
|
||||
githubUsername: string
|
||||
tarballSizeLimit?: number
|
||||
githubToken?: string
|
||||
}): Promise<{
|
||||
error?: string;
|
||||
error?: string
|
||||
data?: {
|
||||
pkgJson: ExtPackageJson;
|
||||
tarballUrl: string;
|
||||
shasum: string;
|
||||
apiVersion: string;
|
||||
tarballSize: number;
|
||||
};
|
||||
pkgJson: ExtPackageJson
|
||||
tarballUrl: string
|
||||
shasum: string
|
||||
apiVersion: string
|
||||
tarballSize: number
|
||||
}
|
||||
}> {
|
||||
// check if jsr package exists
|
||||
const jsrExists = await jsrPackageExists(
|
||||
payload.jsrPackage.scope,
|
||||
payload.jsrPackage.name,
|
||||
payload.jsrPackage.version,
|
||||
);
|
||||
payload.jsrPackage.version
|
||||
)
|
||||
if (!jsrExists) {
|
||||
return { error: "JSR package does not exist" };
|
||||
return { error: "JSR package does not exist" }
|
||||
}
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* check if jsr pkg is linked to a github repo */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
const githubRepo = await getJsrPackageGitHubRepo(
|
||||
payload.jsrPackage.scope,
|
||||
payload.jsrPackage.name,
|
||||
);
|
||||
payload.jsrPackage.name
|
||||
)
|
||||
if (githubRepo === null) {
|
||||
return { error: "JSR package is not linked to a GitHub repository" };
|
||||
return { error: "JSR package is not linked to a GitHub repository" }
|
||||
}
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* check if jsr pkg is signed with github action */
|
||||
@ -295,21 +266,34 @@ export async function validateJsrPackageAsKunkunExtension(payload: {
|
||||
const signed = await isSignedByGitHubAction(
|
||||
payload.jsrPackage.scope,
|
||||
payload.jsrPackage.name,
|
||||
payload.jsrPackage.version,
|
||||
);
|
||||
payload.jsrPackage.version
|
||||
)
|
||||
if (!signed) {
|
||||
return { error: "JSR package is not signed by GitHub Actions" };
|
||||
return { error: "JSR package is not signed by GitHub Actions" }
|
||||
}
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* check if user's github username is the same as repo's owner name */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
if (
|
||||
githubRepo.owner?.toLowerCase() !== payload.githubUsername.toLowerCase()
|
||||
) {
|
||||
return {
|
||||
error:
|
||||
`GitHub repository owner does not match JSR package owner: ${githubRepo.owner} !== ${payload.githubUsername}`,
|
||||
};
|
||||
if (!githubRepo.owner) {
|
||||
return { error: "Package's Linked GitHub repository owner is not found." }
|
||||
}
|
||||
if (githubRepo.owner.toLowerCase() !== payload.githubUsername.toLowerCase()) {
|
||||
const isPublicMemeber = await userIsPublicMemberOfGitHubOrg(
|
||||
githubRepo.owner,
|
||||
payload.githubUsername
|
||||
)
|
||||
let isOrgMember = false
|
||||
if (payload.githubToken) {
|
||||
isOrgMember = await authenticatedUserIsMemberOfGitHubOrg(
|
||||
githubRepo.owner,
|
||||
payload.githubToken
|
||||
)
|
||||
}
|
||||
if (!isPublicMemeber && !isOrgMember) {
|
||||
return {
|
||||
error: `You (${payload.githubUsername}) are not authorized to publish this package. Only ${githubRepo.owner} or its organization members can publish it.`
|
||||
}
|
||||
}
|
||||
}
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* check if jsr.json or deno.json has the same version as package.json */
|
||||
@ -318,60 +302,57 @@ export async function validateJsrPackageAsKunkunExtension(payload: {
|
||||
payload.jsrPackage.scope,
|
||||
payload.jsrPackage.name,
|
||||
payload.jsrPackage.version,
|
||||
"package.json",
|
||||
);
|
||||
"package.json"
|
||||
)
|
||||
if (!packageJsonContent) {
|
||||
return { error: "Could not find package.json in JSR package" };
|
||||
return { error: "Could not find package.json in JSR package" }
|
||||
}
|
||||
let packageJson: any;
|
||||
let packageJson: any
|
||||
try {
|
||||
packageJson = JSON.parse(packageJsonContent);
|
||||
packageJson = JSON.parse(packageJsonContent)
|
||||
} catch (error) {
|
||||
return { error: "Failed to parse package.json" };
|
||||
return { error: "Failed to parse package.json" }
|
||||
}
|
||||
if (packageJson.version !== payload.jsrPackage.version) {
|
||||
// no need to fetch jsr.json or deno.json content, as we already know the version is valid with JSR API
|
||||
return {
|
||||
error:
|
||||
"Package version in package.json does not match JSR package version",
|
||||
};
|
||||
error: "Package version in package.json does not match JSR package version"
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* validate package.json format against latest schema */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
const parseResult = v.safeParse(ExtPackageJson, packageJson);
|
||||
const parseResult = v.safeParse(ExtPackageJson, packageJson)
|
||||
if (!parseResult.success) {
|
||||
return { error: "package.json format not valid" };
|
||||
return { error: "package.json format not valid" }
|
||||
}
|
||||
const npmPkgVersionMetadata = await getJsrNpmPackageVersionMetadata(
|
||||
payload.jsrPackage.scope,
|
||||
payload.jsrPackage.name,
|
||||
payload.jsrPackage.version,
|
||||
);
|
||||
const tarballUrl = npmPkgVersionMetadata.dist.tarball;
|
||||
const shasum = npmPkgVersionMetadata.dist.shasum;
|
||||
payload.jsrPackage.version
|
||||
)
|
||||
const tarballUrl = npmPkgVersionMetadata.dist.tarball
|
||||
const shasum = npmPkgVersionMetadata.dist.shasum
|
||||
if (!tarballUrl) {
|
||||
return { error: "Could not get tarball URL for JSR package" };
|
||||
return { error: "Could not get tarball URL for JSR package" }
|
||||
}
|
||||
const tarballSize = await getTarballSize(tarballUrl);
|
||||
const sizeLimit = payload.tarballSizeLimit ?? 50 * 1024 * 1024; // default to 50MB
|
||||
const tarballSize = await getTarballSize(tarballUrl)
|
||||
const sizeLimit = payload.tarballSizeLimit ?? 50 * 1024 * 1024 // default to 50MB
|
||||
if (tarballSize > sizeLimit) {
|
||||
return {
|
||||
error:
|
||||
`Package tarball size (${tarballSize} bytes) exceeds limit of ${sizeLimit} bytes`,
|
||||
};
|
||||
error: `Package tarball size (${tarballSize} bytes) exceeds limit of ${sizeLimit} bytes`
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* get @kksh/api dependency version */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
const apiVersion = parseResult.output.dependencies?.["@kksh/api"];
|
||||
const apiVersion = parseResult.output.dependencies?.["@kksh/api"]
|
||||
if (!apiVersion) {
|
||||
return {
|
||||
error:
|
||||
`Extension ${packageJson.kunkun.identifier} doesn't not have @kksh/api as a dependency`,
|
||||
};
|
||||
error: `Extension ${packageJson.kunkun.identifier} doesn't not have @kksh/api as a dependency`
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
@ -380,7 +361,7 @@ export async function validateJsrPackageAsKunkunExtension(payload: {
|
||||
tarballUrl,
|
||||
shasum,
|
||||
apiVersion,
|
||||
tarballSize,
|
||||
},
|
||||
};
|
||||
tarballSize
|
||||
}
|
||||
}
|
||||
}
|
||||
|
150
pnpm-lock.yaml
generated
150
pnpm-lock.yaml
generated
@ -342,6 +342,9 @@ importers:
|
||||
'@huakunshen/jsr-client':
|
||||
specifier: ^0.1.5
|
||||
version: 0.1.5(axios@1.7.9)(react@18.3.1)(typescript@5.6.3)
|
||||
'@octokit/rest':
|
||||
specifier: ^21.1.0
|
||||
version: 21.1.0
|
||||
'@tauri-apps/api':
|
||||
specifier: ^2.2.0
|
||||
version: 2.2.0
|
||||
@ -2756,6 +2759,58 @@ packages:
|
||||
'@nuxtjs/tailwindcss@6.12.2':
|
||||
resolution: {integrity: sha512-qPJiFH67CkTj/2kBGBzqXihOD1rQXMsbVS4vdQvfBxOBLPfGhU1yw7AATdhPl2BBjO2krjJLuZj39t7dnDYOwg==}
|
||||
|
||||
'@octokit/auth-token@5.1.1':
|
||||
resolution: {integrity: sha512-rh3G3wDO8J9wSjfI436JUKzHIxq8NaiL0tVeB2aXmG6p/9859aUOAjA9pmSPNGGZxfwmaJ9ozOJImuNVJdpvbA==}
|
||||
engines: {node: '>= 18'}
|
||||
|
||||
'@octokit/core@6.1.3':
|
||||
resolution: {integrity: sha512-z+j7DixNnfpdToYsOutStDgeRzJSMnbj8T1C/oQjB6Aa+kRfNjs/Fn7W6c8bmlt6mfy3FkgeKBRnDjxQow5dow==}
|
||||
engines: {node: '>= 18'}
|
||||
|
||||
'@octokit/endpoint@10.1.2':
|
||||
resolution: {integrity: sha512-XybpFv9Ms4hX5OCHMZqyODYqGTZ3H6K6Vva+M9LR7ib/xr1y1ZnlChYv9H680y77Vd/i/k+thXApeRASBQkzhA==}
|
||||
engines: {node: '>= 18'}
|
||||
|
||||
'@octokit/graphql@8.1.2':
|
||||
resolution: {integrity: sha512-bdlj/CJVjpaz06NBpfHhp4kGJaRZfz7AzC+6EwUImRtrwIw8dIgJ63Xg0OzV9pRn3rIzrt5c2sa++BL0JJ8GLw==}
|
||||
engines: {node: '>= 18'}
|
||||
|
||||
'@octokit/openapi-types@23.0.1':
|
||||
resolution: {integrity: sha512-izFjMJ1sir0jn0ldEKhZ7xegCTj/ObmEDlEfpFrx4k/JyZSMRHbO3/rBwgE7f3m2DHt+RrNGIVw4wSmwnm3t/g==}
|
||||
|
||||
'@octokit/plugin-paginate-rest@11.4.0':
|
||||
resolution: {integrity: sha512-ttpGck5AYWkwMkMazNCZMqxKqIq1fJBNxBfsFwwfyYKTf914jKkLF0POMS3YkPBwp5g1c2Y4L79gDz01GhSr1g==}
|
||||
engines: {node: '>= 18'}
|
||||
peerDependencies:
|
||||
'@octokit/core': '>=6'
|
||||
|
||||
'@octokit/plugin-request-log@5.3.1':
|
||||
resolution: {integrity: sha512-n/lNeCtq+9ofhC15xzmJCNKP2BWTv8Ih2TTy+jatNCCq/gQP/V7rK3fjIfuz0pDWDALO/o/4QY4hyOF6TQQFUw==}
|
||||
engines: {node: '>= 18'}
|
||||
peerDependencies:
|
||||
'@octokit/core': '>=6'
|
||||
|
||||
'@octokit/plugin-rest-endpoint-methods@13.3.0':
|
||||
resolution: {integrity: sha512-LUm44shlmkp/6VC+qQgHl3W5vzUP99ZM54zH6BuqkJK4DqfFLhegANd+fM4YRLapTvPm4049iG7F3haANKMYvQ==}
|
||||
engines: {node: '>= 18'}
|
||||
peerDependencies:
|
||||
'@octokit/core': '>=6'
|
||||
|
||||
'@octokit/request-error@6.1.6':
|
||||
resolution: {integrity: sha512-pqnVKYo/at0NuOjinrgcQYpEbv4snvP3bKMRqHaD9kIsk9u1LCpb2smHZi8/qJfgeNqLo5hNW4Z7FezNdEo0xg==}
|
||||
engines: {node: '>= 18'}
|
||||
|
||||
'@octokit/request@9.1.4':
|
||||
resolution: {integrity: sha512-tMbOwGm6wDII6vygP3wUVqFTw3Aoo0FnVQyhihh8vVq12uO3P+vQZeo2CKMpWtPSogpACD0yyZAlVlQnjW71DA==}
|
||||
engines: {node: '>= 18'}
|
||||
|
||||
'@octokit/rest@21.1.0':
|
||||
resolution: {integrity: sha512-93iLxcKDJboUpmnUyeJ6cRIi7z7cqTZT1K7kRK4LobGxwTwpsa+2tQQbRQNGy7IFDEAmrtkf4F4wBj3D5rVlJQ==}
|
||||
engines: {node: '>= 18'}
|
||||
|
||||
'@octokit/types@13.7.0':
|
||||
resolution: {integrity: sha512-BXfRP+3P3IN6fd4uF3SniaHKOO4UXWBfkdR3vA8mIvaoO/wLjGN5qivUtW0QRitBHHMcfC41SLhNVYIZZE+wkA==}
|
||||
|
||||
'@parcel/watcher-android-arm64@2.5.0':
|
||||
resolution: {integrity: sha512-qlX4eS28bUcQCdribHkg/herLe+0A9RyYC+mm2PXpncit8z5b3nSqGVzMNR3CmtAOgRutiZ02eIJJgP/b1iEFQ==}
|
||||
engines: {node: '>= 10.0.0'}
|
||||
@ -5551,6 +5606,9 @@ packages:
|
||||
bcrypt-pbkdf@1.0.2:
|
||||
resolution: {integrity: sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==}
|
||||
|
||||
before-after-hook@3.0.2:
|
||||
resolution: {integrity: sha512-Nik3Sc0ncrMK4UUdXQmAnRtzmNQTAAXmXIopizwZ1W1t8QmfJj+zL4OA2I7XPTPW5z5TDqv4hRo/JzouDJnX3A==}
|
||||
|
||||
better-path-resolve@1.0.0:
|
||||
resolution: {integrity: sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==}
|
||||
engines: {node: '>=4'}
|
||||
@ -6890,6 +6948,9 @@ packages:
|
||||
resolution: {integrity: sha512-TmpgSeJ2jUV+FNWnSy9iIE9bOV9nCNQ4it+K9BpCNT9JsQOfZYznWGSbMw+Wa4uusEss0IcL/trFVoRxS6IuAA==}
|
||||
engines: {node: '>=8.0.0'}
|
||||
|
||||
fast-content-type-parse@2.0.1:
|
||||
resolution: {integrity: sha512-nGqtvLrj5w0naR6tDPfB4cUmYCqouzyQiz6C5y/LtcDllJdrcc6WaWW6iXyIIOErTa/XRybj28aasdn4LkVk6Q==}
|
||||
|
||||
fast-deep-equal@3.1.3:
|
||||
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
|
||||
|
||||
@ -10296,6 +10357,9 @@ packages:
|
||||
unist-util-visit@5.0.0:
|
||||
resolution: {integrity: sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==}
|
||||
|
||||
universal-user-agent@7.0.2:
|
||||
resolution: {integrity: sha512-0JCqzSKnStlRRQfCdowvqy3cy0Dvtlb8xecj/H8JFZuCze4rwjPZQOgvFvn0Ws/usCHQFGpyr+pB9adaGwXn4Q==}
|
||||
|
||||
universalify@0.1.2:
|
||||
resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==}
|
||||
engines: {node: '>= 4.0.0'}
|
||||
@ -13098,6 +13162,68 @@ snapshots:
|
||||
- supports-color
|
||||
- ts-node
|
||||
|
||||
'@octokit/auth-token@5.1.1': {}
|
||||
|
||||
'@octokit/core@6.1.3':
|
||||
dependencies:
|
||||
'@octokit/auth-token': 5.1.1
|
||||
'@octokit/graphql': 8.1.2
|
||||
'@octokit/request': 9.1.4
|
||||
'@octokit/request-error': 6.1.6
|
||||
'@octokit/types': 13.7.0
|
||||
before-after-hook: 3.0.2
|
||||
universal-user-agent: 7.0.2
|
||||
|
||||
'@octokit/endpoint@10.1.2':
|
||||
dependencies:
|
||||
'@octokit/types': 13.7.0
|
||||
universal-user-agent: 7.0.2
|
||||
|
||||
'@octokit/graphql@8.1.2':
|
||||
dependencies:
|
||||
'@octokit/request': 9.1.4
|
||||
'@octokit/types': 13.7.0
|
||||
universal-user-agent: 7.0.2
|
||||
|
||||
'@octokit/openapi-types@23.0.1': {}
|
||||
|
||||
'@octokit/plugin-paginate-rest@11.4.0(@octokit/core@6.1.3)':
|
||||
dependencies:
|
||||
'@octokit/core': 6.1.3
|
||||
'@octokit/types': 13.7.0
|
||||
|
||||
'@octokit/plugin-request-log@5.3.1(@octokit/core@6.1.3)':
|
||||
dependencies:
|
||||
'@octokit/core': 6.1.3
|
||||
|
||||
'@octokit/plugin-rest-endpoint-methods@13.3.0(@octokit/core@6.1.3)':
|
||||
dependencies:
|
||||
'@octokit/core': 6.1.3
|
||||
'@octokit/types': 13.7.0
|
||||
|
||||
'@octokit/request-error@6.1.6':
|
||||
dependencies:
|
||||
'@octokit/types': 13.7.0
|
||||
|
||||
'@octokit/request@9.1.4':
|
||||
dependencies:
|
||||
'@octokit/endpoint': 10.1.2
|
||||
'@octokit/request-error': 6.1.6
|
||||
'@octokit/types': 13.7.0
|
||||
fast-content-type-parse: 2.0.1
|
||||
universal-user-agent: 7.0.2
|
||||
|
||||
'@octokit/rest@21.1.0':
|
||||
dependencies:
|
||||
'@octokit/core': 6.1.3
|
||||
'@octokit/plugin-paginate-rest': 11.4.0(@octokit/core@6.1.3)
|
||||
'@octokit/plugin-request-log': 5.3.1(@octokit/core@6.1.3)
|
||||
'@octokit/plugin-rest-endpoint-methods': 13.3.0(@octokit/core@6.1.3)
|
||||
|
||||
'@octokit/types@13.7.0':
|
||||
dependencies:
|
||||
'@octokit/openapi-types': 23.0.1
|
||||
|
||||
'@parcel/watcher-android-arm64@2.5.0':
|
||||
optional: true
|
||||
|
||||
@ -16393,6 +16519,8 @@ snapshots:
|
||||
dependencies:
|
||||
tweetnacl: 0.14.5
|
||||
|
||||
before-after-hook@3.0.2: {}
|
||||
|
||||
better-path-resolve@1.0.0:
|
||||
dependencies:
|
||||
is-windows: 1.0.2
|
||||
@ -17601,8 +17729,8 @@ snapshots:
|
||||
'@typescript-eslint/parser': 8.15.0(eslint@8.57.1)(typescript@5.6.3)
|
||||
eslint: 8.57.1
|
||||
eslint-import-resolver-node: 0.3.9
|
||||
eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1))(eslint@8.57.1)
|
||||
eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1)
|
||||
eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.57.1)
|
||||
eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1)
|
||||
eslint-plugin-jsx-a11y: 6.10.2(eslint@8.57.1)
|
||||
eslint-plugin-react: 7.37.2(eslint@8.57.1)
|
||||
eslint-plugin-react-hooks: 5.0.0(eslint@8.57.1)
|
||||
@ -17630,37 +17758,37 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1))(eslint@8.57.1):
|
||||
eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.57.1):
|
||||
dependencies:
|
||||
'@nolyfill/is-core-module': 1.0.39
|
||||
debug: 4.4.0(supports-color@9.4.0)
|
||||
enhanced-resolve: 5.17.1
|
||||
eslint: 8.57.1
|
||||
eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1)
|
||||
eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1)
|
||||
fast-glob: 3.3.2
|
||||
get-tsconfig: 4.8.1
|
||||
is-bun-module: 1.2.1
|
||||
is-glob: 4.0.3
|
||||
optionalDependencies:
|
||||
eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1)
|
||||
eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1)
|
||||
transitivePeerDependencies:
|
||||
- '@typescript-eslint/parser'
|
||||
- eslint-import-resolver-node
|
||||
- eslint-import-resolver-webpack
|
||||
- supports-color
|
||||
|
||||
eslint-module-utils@2.12.0(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1):
|
||||
eslint-module-utils@2.12.0(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1):
|
||||
dependencies:
|
||||
debug: 3.2.7
|
||||
optionalDependencies:
|
||||
'@typescript-eslint/parser': 8.15.0(eslint@8.57.1)(typescript@5.6.3)
|
||||
eslint: 8.57.1
|
||||
eslint-import-resolver-node: 0.3.9
|
||||
eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1))(eslint@8.57.1)
|
||||
eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.57.1)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1):
|
||||
eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1):
|
||||
dependencies:
|
||||
'@rtsao/scc': 1.1.0
|
||||
array-includes: 3.1.8
|
||||
@ -17671,7 +17799,7 @@ snapshots:
|
||||
doctrine: 2.1.0
|
||||
eslint: 8.57.1
|
||||
eslint-import-resolver-node: 0.3.9
|
||||
eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1)
|
||||
eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1)
|
||||
hasown: 2.0.2
|
||||
is-core-module: 2.15.1
|
||||
is-glob: 4.0.3
|
||||
@ -17981,6 +18109,8 @@ snapshots:
|
||||
pure-rand: 6.1.0
|
||||
optional: true
|
||||
|
||||
fast-content-type-parse@2.0.1: {}
|
||||
|
||||
fast-deep-equal@3.1.3: {}
|
||||
|
||||
fast-equals@5.0.1: {}
|
||||
@ -21902,6 +22032,8 @@ snapshots:
|
||||
unist-util-is: 6.0.0
|
||||
unist-util-visit-parents: 6.0.1
|
||||
|
||||
universal-user-agent@7.0.2: {}
|
||||
|
||||
universalify@0.1.2: {}
|
||||
|
||||
universalify@2.0.1: {}
|
||||
|
Loading…
x
Reference in New Issue
Block a user