fix: support GitPeji tags and interactive helper auth
APT build checks / build-checks (push) Has been cancelled
APT build checks / build-checks (push) Has been cancelled
This commit is contained in:
+1
-1
@@ -111,7 +111,7 @@ function createProxyManager({
|
|||||||
{
|
{
|
||||||
shell: false,
|
shell: false,
|
||||||
detached: true,
|
detached: true,
|
||||||
stdio: 'ignore',
|
stdio: 'inherit',
|
||||||
windowsHide: false
|
windowsHide: false
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
+10
-4
@@ -8,7 +8,7 @@ const REQUEST_TIMEOUT_MS = 5000;
|
|||||||
const MAX_BODY_BYTES = 64 * 1024;
|
const MAX_BODY_BYTES = 64 * 1024;
|
||||||
const MAX_RELEASE_NAME_LENGTH = 200;
|
const MAX_RELEASE_NAME_LENGTH = 200;
|
||||||
|
|
||||||
// SemVer 2.0.0 without loose forms such as a leading "v" or omitted fields.
|
// Strict SemVer 2.0.0 without loose forms such as omitted fields.
|
||||||
const SEMVER_PATTERN = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*)(?:\.(?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*))*))?(?:\+([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?$/;
|
const SEMVER_PATTERN = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*)(?:\.(?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*))*))?(?:\+([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?$/;
|
||||||
|
|
||||||
class UpdatePolicyError extends Error {
|
class UpdatePolicyError extends Error {
|
||||||
@@ -41,6 +41,12 @@ function parseSemver(version, errorCode = 'INVALID_VERSION') {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function normalizeReleaseTag(tag) {
|
||||||
|
const version = tag.startsWith('v') ? tag.slice(1) : tag;
|
||||||
|
parseSemver(version, 'INVALID_RELEASE_VERSION');
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
function compareIdentifier(left, right) {
|
function compareIdentifier(left, right) {
|
||||||
const leftNumeric = /^\d+$/.test(left);
|
const leftNumeric = /^\d+$/.test(left);
|
||||||
const rightNumeric = /^\d+$/.test(right);
|
const rightNumeric = /^\d+$/.test(right);
|
||||||
@@ -290,14 +296,14 @@ async function checkForUpdate({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const release = parseRelease(body);
|
const release = parseRelease(body);
|
||||||
parseSemver(release.latestVersion, 'INVALID_RELEASE_VERSION');
|
const latestVersion = normalizeReleaseTag(release.latestVersion);
|
||||||
|
|
||||||
const metadata = {
|
const metadata = {
|
||||||
status: compareSemver(release.latestVersion, currentVersion) > 0
|
status: compareSemver(latestVersion, currentVersion) > 0
|
||||||
? 'update-available'
|
? 'update-available'
|
||||||
: 'up-to-date',
|
: 'up-to-date',
|
||||||
...baseMetadata,
|
...baseMetadata,
|
||||||
latestVersion: release.latestVersion,
|
latestVersion,
|
||||||
releaseName: release.releaseName,
|
releaseName: release.releaseName,
|
||||||
};
|
};
|
||||||
if (release.publishedAt !== undefined) {
|
if (release.publishedAt !== undefined) {
|
||||||
|
|||||||
+15
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"id": 17,
|
||||||
|
"tag_name": "v1.0.0",
|
||||||
|
"target_commitish": "main",
|
||||||
|
"name": "Alta Proxy Tool v1.0.0",
|
||||||
|
"body": "Initial GitPeji release",
|
||||||
|
"draft": false,
|
||||||
|
"prerelease": false,
|
||||||
|
"created_at": "2026-08-19T12:30:00Z",
|
||||||
|
"published_at": "2026-08-19T12:34:56Z",
|
||||||
|
"html_url": "https://git.pejicorp.com/peji/Alta-Proxy-Tool/releases/tag/v1.0.0",
|
||||||
|
"tarball_url": "https://git.pejicorp.com/peji/Alta-Proxy-Tool/archive/v1.0.0.tar.gz",
|
||||||
|
"zipball_url": "https://git.pejicorp.com/peji/Alta-Proxy-Tool/archive/v1.0.0.zip",
|
||||||
|
"assets": []
|
||||||
|
}
|
||||||
@@ -65,7 +65,7 @@ test('exports the proxy manager module', () => {
|
|||||||
assert.doesNotThrow(() => loadModule());
|
assert.doesNotThrow(() => loadModule());
|
||||||
});
|
});
|
||||||
|
|
||||||
test('launches the approved helper directly with exact argv and shell disabled', () => {
|
test('launches the approved helper directly in a visible interactive console', () => {
|
||||||
const { manager, calls } = createHarness();
|
const { manager, calls } = createHarness();
|
||||||
|
|
||||||
const result = manager.launchProxy(validRequest());
|
const result = manager.launchProxy(validRequest());
|
||||||
@@ -76,7 +76,7 @@ test('launches the approved helper directly with exact argv and shell disabled',
|
|||||||
{
|
{
|
||||||
shell: false,
|
shell: false,
|
||||||
detached: true,
|
detached: true,
|
||||||
stdio: 'ignore',
|
stdio: 'inherit',
|
||||||
windowsHide: false
|
windowsHide: false
|
||||||
}
|
}
|
||||||
]]);
|
]]);
|
||||||
@@ -97,6 +97,8 @@ test('passes username punctuation literally in argv without invoking a shell', (
|
|||||||
|
|
||||||
assert.equal(calls[0][1][3], username);
|
assert.equal(calls[0][1][3], username);
|
||||||
assert.equal(calls[0][2].shell, false);
|
assert.equal(calls[0][2].shell, false);
|
||||||
|
assert.equal(calls[0][2].stdio, 'inherit');
|
||||||
|
assert.notEqual(calls[0][2].stdio, 'ignore');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('rejects the CRLF calc.exe reproducer in every structured input', () => {
|
test('rejects the CRLF calc.exe reproducer in every structured input', () => {
|
||||||
|
|||||||
@@ -3,6 +3,8 @@
|
|||||||
const assert = require('node:assert/strict');
|
const assert = require('node:assert/strict');
|
||||||
const test = require('node:test');
|
const test = require('node:test');
|
||||||
const { EventEmitter } = require('node:events');
|
const { EventEmitter } = require('node:events');
|
||||||
|
const fs = require('node:fs');
|
||||||
|
const path = require('node:path');
|
||||||
|
|
||||||
const {
|
const {
|
||||||
LATEST_RELEASE_URL,
|
LATEST_RELEASE_URL,
|
||||||
@@ -30,6 +32,24 @@ async function rejectsWithCode(promise, code) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test('accepts a live-shape GitPeji v-tag and normalizes it to bare semver', async () => {
|
||||||
|
const fixture = fs.readFileSync(
|
||||||
|
path.join(__dirname, 'fixtures', 'gitpeji-latest-release.json'),
|
||||||
|
'utf8',
|
||||||
|
);
|
||||||
|
|
||||||
|
const result = await checkForUpdate({
|
||||||
|
currentVersion: '0.9.0',
|
||||||
|
request: async () => response(fixture),
|
||||||
|
platform: 'win32',
|
||||||
|
arch: 'x64',
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.equal(result.status, 'update-available');
|
||||||
|
assert.equal(result.latestVersion, '1.0.0');
|
||||||
|
assert.equal(result.releaseName, 'Alta Proxy Tool v1.0.0');
|
||||||
|
});
|
||||||
|
|
||||||
test('valid update returns only sanitized, check-only metadata', async () => {
|
test('valid update returns only sanitized, check-only metadata', async () => {
|
||||||
let requestOptions;
|
let requestOptions;
|
||||||
const request = async (options) => {
|
const request = async (options) => {
|
||||||
@@ -148,7 +168,20 @@ test('redirects and response host drift are rejected', async () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('invalid or non-strict semver fails closed', async () => {
|
test('invalid or non-strict semver fails closed', async () => {
|
||||||
const invalidVersions = ['v1.2.3', '1.2', '01.2.3', '1.2.3.4', 'latest'];
|
const invalidVersions = [
|
||||||
|
'V1.2.3',
|
||||||
|
'vv1.2.3',
|
||||||
|
' v1.2.3',
|
||||||
|
'v1.2.3 ',
|
||||||
|
'v1.2',
|
||||||
|
'v01.2.3',
|
||||||
|
'v1.2.3.4',
|
||||||
|
'vlatest',
|
||||||
|
'1.2',
|
||||||
|
'01.2.3',
|
||||||
|
'1.2.3.4',
|
||||||
|
'latest',
|
||||||
|
];
|
||||||
|
|
||||||
for (const tag_name of invalidVersions) {
|
for (const tag_name of invalidVersions) {
|
||||||
await rejectsWithCode(
|
await rejectsWithCode(
|
||||||
|
|||||||
Reference in New Issue
Block a user