Compare commits
18 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| db83b3ee11 | |||
| b17a8757b2 | |||
| 58479c7c6d | |||
| 0de87d6629 | |||
| bc914c401c | |||
| 27e471d9e0 | |||
| f1c21beed5 | |||
| 3c3019d1ab | |||
| 41a8fe100f | |||
| c1c00449af | |||
| ef3654b091 | |||
| 5d0c9fd691 | |||
| 5860588588 | |||
| 53a7ec7a3e | |||
| 42241c5000 | |||
| 1a12ec4e2e | |||
| a90886e924 | |||
| 57285ce145 |
@@ -3,9 +3,5 @@
|
|||||||
"role": "Rex",
|
"role": "Rex",
|
||||||
"location": "app/git.js",
|
"location": "app/git.js",
|
||||||
"suggestion": "請避免將敏感資料(如 GITEA_TOKEN)直接寫入環境變數"
|
"suggestion": "請避免將敏感資料(如 GITEA_TOKEN)直接寫入環境變數"
|
||||||
},
|
|
||||||
{
|
|
||||||
"location": "app/git.js",
|
|
||||||
"suggestion": "GITEA_TOKEN 直接嵌入 URL 中"
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1 +1,37 @@
|
|||||||
[]
|
[
|
||||||
|
{
|
||||||
|
"level": "critical",
|
||||||
|
"role": "Rex",
|
||||||
|
"location": "app/git.js:14",
|
||||||
|
"suggestion": "請避免將 GIT_TOKEN 直接寫入腳本中,應使用安全的秘密管理工具來管理這些敏感資訊.",
|
||||||
|
"is_new": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"level": "warning",
|
||||||
|
"role": "Leo",
|
||||||
|
"location": "app/git.js:14",
|
||||||
|
"suggestion": "建議在 cloneRepo 函數中增加對於 GIT_TOKEN 的安全性處理,避免敏感資訊洩漏.",
|
||||||
|
"is_new": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"level": "warning",
|
||||||
|
"role": "Leo",
|
||||||
|
"location": "app/findings.js:93",
|
||||||
|
"suggestion": "建議在 loadExclusions 函式中增加對於 JSON 格式的驗證,確保讀取的資料符合預期格式,避免潛在的錯誤.",
|
||||||
|
"is_new": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"level": "warning",
|
||||||
|
"role": "Leo",
|
||||||
|
"location": "app/findings.js:40",
|
||||||
|
"suggestion": "在 applyExclusions 函式中,建議增加對於 findings 和 exclusions 參數的有效性檢查,以提高程式的健壯性.",
|
||||||
|
"is_new": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"level": "info",
|
||||||
|
"role": "Leo",
|
||||||
|
"location": "README.md",
|
||||||
|
"suggestion": "建議在 README 中增加對於新功能(如排除問題過濾)的詳細說明,以便未來的維護者能快速了解其功能.",
|
||||||
|
"is_new": true
|
||||||
|
}
|
||||||
|
]
|
||||||
+1
-57
@@ -3,7 +3,7 @@ import assert from 'node:assert/strict';
|
|||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import os from 'os';
|
import os from 'os';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import { commitAndPush, cloneRepo } from './git.js';
|
import { commitAndPush } from './git.js';
|
||||||
|
|
||||||
// --- helpers ---
|
// --- helpers ---
|
||||||
function makeTmpWorkspace() {
|
function makeTmpWorkspace() {
|
||||||
@@ -91,59 +91,3 @@ describe('commitAndPush', () => {
|
|||||||
await assert.doesNotReject(() => commitAndPush(workspace, failSpawn));
|
await assert.doesNotReject(() => commitAndPush(workspace, failSpawn));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('cloneRepo', () => {
|
|
||||||
let workspace;
|
|
||||||
|
|
||||||
before(() => { workspace = fs.mkdtempSync(path.join(os.tmpdir(), 'clone-test-')); });
|
|
||||||
after(() => { fs.rmSync(workspace, { recursive: true, force: true }); });
|
|
||||||
|
|
||||||
it('clones repo when repoDir does not exist', () => {
|
|
||||||
const spawn = makeSpawn();
|
|
||||||
cloneRepo(workspace, spawn);
|
|
||||||
const cloneCalled = spawn.calls.some(c => c.args[0] === 'clone');
|
|
||||||
assert.ok(cloneCalled, 'expected git clone to be called');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('fetches and checks out when repoDir already exists', () => {
|
|
||||||
const repoDir = path.join(workspace, 'repo');
|
|
||||||
fs.mkdirSync(repoDir, { recursive: true });
|
|
||||||
const spawn = makeSpawn();
|
|
||||||
cloneRepo(workspace, spawn);
|
|
||||||
const cloneCalled = spawn.calls.some(c => c.args[0] === 'clone');
|
|
||||||
const fetchCalled = spawn.calls.some(c => c.args[0] === 'fetch');
|
|
||||||
assert.ok(!cloneCalled, 'clone should not run when repoDir exists');
|
|
||||||
assert.ok(fetchCalled, 'fetch should run when repoDir exists');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('does not embed token in any git command argument', () => {
|
|
||||||
const spawn = makeSpawn();
|
|
||||||
cloneRepo(workspace, spawn);
|
|
||||||
for (const { args } of spawn.calls) {
|
|
||||||
assert.ok(!args.join(' ').includes('test-token'), `Token leaked in git args: ${args.join(' ')}`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
it('uses GIT_ASKPASS for network operations', () => {
|
|
||||||
const spawn = makeSpawn();
|
|
||||||
cloneRepo(workspace, spawn);
|
|
||||||
const networkCalls = spawn.calls.filter(c => ['clone', 'fetch'].includes(c.args[0]));
|
|
||||||
assert.ok(networkCalls.length > 0, 'expected at least one network git call');
|
|
||||||
for (const { args, opts } of networkCalls) {
|
|
||||||
assert.ok(opts?.env?.GIT_ASKPASS, `GIT_ASKPASS missing for git ${args[0]}`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
it('cleans up askpass script after run', () => {
|
|
||||||
const spawn = makeSpawn();
|
|
||||||
cloneRepo(workspace, spawn);
|
|
||||||
const leftover = fs.readdirSync(workspace).filter(f => f.endsWith('.git-askpass.sh'));
|
|
||||||
assert.equal(leftover.length, 0, 'askpass script was not cleaned up');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns repoDir path', () => {
|
|
||||||
const spawn = makeSpawn();
|
|
||||||
const result = cloneRepo(workspace, spawn);
|
|
||||||
assert.equal(result, path.join(workspace, 'repo'));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|||||||
Reference in New Issue
Block a user