Skip to content

Commit 8550358

Browse files
authored
Merge pull request #3 from ranade-oss/agent/ross-020-browser-permission-fix
Make website scripts browser-upload safe
2 parents 99c09a9 + 74e95ab commit 8550358

6 files changed

Lines changed: 81 additions & 4 deletions

File tree

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ node_modules
33
dist
44
out
55
build
6+
!website/build/
7+
!website/build/sites-vite-plugin.ts
68
.open-next
79

810
.env

tests/baseline/ross-website-contract.test.mjs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,40 @@ test("the public website is a separate build target", () => {
1212
const rootPackage = json("package.json");
1313
const websitePackage = json("website/package.json");
1414
assert.equal(existsSync(resolve(root, "website/.openai/hosting.json")), true);
15+
assert.equal(existsSync(resolve(root, "website/build/sites-vite-plugin.ts")), true);
1516
assert.equal(websitePackage.name, "ross-ontario");
1617
assert.match(rootPackage.scripts["install:all"], /--prefix website/);
1718
assert.match(rootPackage.scripts.build, /build:website/);
1819
assert.match(rootPackage.scripts.lint, /lint:website/);
1920
assert.match(rootPackage.scripts.check, /test:website/);
2021
});
2122

23+
test("the website build plugin is deliberately tracked", () => {
24+
const ignoreRules = read(".gitignore");
25+
assert.match(ignoreRules, /!website\/build\//);
26+
assert.match(ignoreRules, /!website\/build\/sites-vite-plugin\.ts/);
27+
assert.match(read("website/vite.config.ts"), /\.\/build\/sites-vite-plugin/);
28+
});
29+
30+
test("website shell helpers survive browser uploads without executable modes", () => {
31+
const wrappers = [
32+
"website/scripts/build-verified.sh",
33+
"website/scripts/install-ci.sh",
34+
"website/scripts/validate-artifact.sh",
35+
];
36+
for (const wrapper of wrappers) {
37+
assert.match(
38+
read(wrapper),
39+
/exec bash "\$\{script_dir\}\/sites-env\.sh" -- bash "\$0" "\$@"/,
40+
wrapper,
41+
);
42+
}
43+
assert.match(
44+
read("website/scripts/build-verified.sh"),
45+
/bash "\$\{script_dir\}\/validate-artifact\.sh"/,
46+
);
47+
});
48+
2249
test("the public website derives identity and policy from central configuration", () => {
2350
const central = json("config/ross-brand.json");
2451
const siteConfig = read("website/app/site-config.ts");

website/build/sites-vite-plugin.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { access, cp, mkdir, rm } from "node:fs/promises";
2+
import { resolve } from "node:path";
3+
import type { Plugin } from "vite";
4+
5+
async function exists(path: string): Promise<boolean> {
6+
try {
7+
await access(path);
8+
return true;
9+
} catch (error) {
10+
if ((error as NodeJS.ErrnoException).code === "ENOENT") {
11+
return false;
12+
}
13+
throw error;
14+
}
15+
}
16+
17+
// Packages Sites metadata and migrations after Vite finishes compiling.
18+
export function sites(): Plugin {
19+
let root = process.cwd();
20+
21+
return {
22+
name: "sites",
23+
apply: "build",
24+
configResolved(config) {
25+
root = config.root;
26+
},
27+
async closeBundle() {
28+
const outputDirectory = resolve(root, "dist", ".openai");
29+
const hostingConfig = resolve(root, ".openai", "hosting.json");
30+
const drizzleSource = resolve(root, "drizzle");
31+
32+
await rm(outputDirectory, { recursive: true, force: true });
33+
await mkdir(outputDirectory, { recursive: true });
34+
35+
if (await exists(hostingConfig)) {
36+
await cp(hostingConfig, resolve(outputDirectory, "hosting.json"));
37+
}
38+
if (await exists(drizzleSource)) {
39+
await cp(drizzleSource, resolve(outputDirectory, "drizzle"), {
40+
recursive: true,
41+
});
42+
}
43+
},
44+
};
45+
}

website/scripts/build-verified.sh

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ set -euo pipefail
44
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
55

66
if [[ "${SITES_ENV_READY:-}" != "1" ]]; then
7-
exec "${script_dir}/sites-env.sh" -- "$0" "$@"
7+
# Browser-based GitHub uploads do not preserve executable file modes.
8+
exec bash "${script_dir}/sites-env.sh" -- bash "$0" "$@"
89
fi
910

1011
command -v timeout >/dev/null || {
@@ -25,4 +26,4 @@ timeout \
2526
"${SITES_BUILD_TIMEOUT:-3m}" \
2627
"${vinext}" build
2728

28-
"${script_dir}/validate-artifact.sh"
29+
bash "${script_dir}/validate-artifact.sh"

website/scripts/install-ci.sh

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ set -euo pipefail
44
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
55

66
if [[ "${SITES_ENV_READY:-}" != "1" ]]; then
7-
exec "${script_dir}/sites-env.sh" -- "$0" "$@"
7+
# Browser-based GitHub uploads do not preserve executable file modes.
8+
exec bash "${script_dir}/sites-env.sh" -- bash "$0" "$@"
89
fi
910

1011
command -v flock >/dev/null || {

website/scripts/validate-artifact.sh

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ set -euo pipefail
44
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
55

66
if [[ "${SITES_ENV_READY:-}" != "1" ]]; then
7-
exec "${script_dir}/sites-env.sh" -- "$0" "$@"
7+
# Browser-based GitHub uploads do not preserve executable file modes.
8+
exec bash "${script_dir}/sites-env.sh" -- bash "$0" "$@"
89
fi
910

1011
worker="${SITES_PROJECT_ROOT}/dist/server/index.js"

0 commit comments

Comments
 (0)