Compare commits

..
Author SHA1 Message Date
copilot-swe-agent[bot]andwhyour 60f8286825 Preserve original TMPDIR value when setting temporary directory
Improve git_clone_scripts to save and restore the original TMPDIR value instead of unconditionally unsetting it, avoiding unintended side effects.

Co-authored-by: whyour <22700758+whyour@users.noreply.github.com>
2026-01-03 06:56:08 +00:00
copilot-swe-agent[bot]andwhyour 7deab5d18e Fix subscription git clone failure by setting TMPDIR
Set TMPDIR=/tmp before git clone operations to fix "unable to get random bytes for temporary file" error in Docker environments with restricted system calls (e.g., Synology NAS).

Co-authored-by: whyour <22700758+whyour@users.noreply.github.com>
2026-01-03 06:55:05 +00:00
copilot-swe-agent[bot] 4fd89ab155 Initial plan 2026-01-03 06:51:43 +00:00
2 changed files with 13 additions and 34 deletions
+5 -34
View File
@@ -13,29 +13,9 @@ import { isValidToken } from '../shared/auth';
import path from 'path';
export default ({ app }: { app: Application }) => {
// Security: Enable strict routing to prevent case-insensitive path bypass
app.set('case sensitive routing', true);
app.set('strict routing', true);
app.set('trust proxy', 'loopback');
app.use(cors());
// Security: Path normalization middleware to prevent case variation attacks
app.use((req, res, next) => {
const originalPath = req.path;
const normalizedPath = originalPath.toLowerCase();
// Block requests with case variations on protected paths
if (originalPath !== normalizedPath &&
(normalizedPath.startsWith('/api/') || normalizedPath.startsWith('/open/'))) {
return res.status(400).json({
code: 400,
message: 'Invalid path format'
});
}
next();
});
// Rewrite URLs to strip baseUrl prefix if configured
// This allows the rest of the app to work without baseUrl awareness
if (config.baseUrl) {
@@ -56,7 +36,7 @@ export default ({ app }: { app: Application }) => {
secret: config.jwt.secret,
algorithms: ['HS384'],
}).unless({
path: [...config.apiWhiteList, /^(\/(?!api\/).*)$/i],
path: [...config.apiWhiteList, /^\/(?!api\/).*/],
}),
);
@@ -71,20 +51,19 @@ export default ({ app }: { app: Application }) => {
});
app.use(async (req: Request, res, next) => {
const pathLower = req.path.toLowerCase();
if (!['/open/', '/api/'].some((x) => pathLower.startsWith(x))) {
if (!['/open/', '/api/'].some((x) => req.path.startsWith(x))) {
return next();
}
const headerToken = getToken(req);
if (pathLower.startsWith('/open/')) {
if (req.path.startsWith('/open/')) {
const apps = await shareStore.getApps();
const doc = apps?.filter((x) =>
x.tokens?.find((y) => y.value === headerToken),
)?.[0];
if (doc && doc.tokens && doc.tokens.length > 0) {
const currentToken = doc.tokens.find((x) => x.value === headerToken);
const keyMatch = pathLower.match(/\/open\/([a-z]+)\/*/);
const keyMatch = req.path.match(/\/open\/([a-z]+)\/*/);
const key = keyMatch && keyMatch[1];
if (
doc.scopes.includes(key as any) &&
@@ -119,15 +98,7 @@ export default ({ app }: { app: Application }) => {
});
app.use(async (req, res, next) => {
const pathLower = req.path.toLowerCase();
if (
![
'/api/user/init',
'/api/user/notification/init',
'/open/user/init',
'/open/user/notification/init',
].includes(req.path)
) {
if (!['/api/user/init', '/api/user/notification/init'].includes(req.path)) {
return next();
}
const authInfo =
+8
View File
@@ -258,8 +258,16 @@ git_clone_scripts() {
set_proxy "$proxy"
# Set TMPDIR to /tmp to avoid "unable to get random bytes" error in some Docker environments
local original_tmpdir="${TMPDIR:-}"
export TMPDIR=/tmp
git clone -q --depth=1 $part_cmd $url $dir
exit_status=$?
if [[ -n "$original_tmpdir" ]]; then
export TMPDIR="$original_tmpdir"
else
unset TMPDIR
fi
unset_proxy
}