Skip to content

refactor: refactor git-proxy-cli to TS + ESM #1065

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 33 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
e0c61ca
refactor(ts): OIDC passport strategy
jescalada Jun 24, 2025
75c4b25
refactor(ts): local passport strategy
jescalada Jun 24, 2025
ba0dad1
refactor(ts): AD passport strategy and test fixes
jescalada Jun 24, 2025
60b51c8
refactor(ts): passport helper files
jescalada Jun 25, 2025
c93fe25
refactor(ts): JWT auth handler and main passport handler
jescalada Jun 25, 2025
4706ee5
chore(ts): add types for JWT-related libraries
jescalada Jun 25, 2025
d94d1db
refactor(ts): service helper functions
jescalada Jun 26, 2025
19049eb
refactor(ts): service module auth routes
jescalada Jun 26, 2025
a2b5aae
refactor(ts): service index file
jescalada Jun 27, 2025
08269c8
ts(refactor): service push routes
jescalada Jun 27, 2025
885c061
refactor(ts): service module helpers and minor fixes
jescalada Jun 27, 2025
c7502b2
refactor(ts): service repo routes, add missing library types
jescalada Jun 27, 2025
b632de5
refactor(ts): service module users routes
jescalada Jun 27, 2025
920a0a6
refactor(ts): cli index file
jescalada Jun 29, 2025
89e221b
refactor(ts): add appropriate TS config and node scripts
jescalada Jun 29, 2025
8802193
chore(ts): update CLI run script
jescalada Jun 29, 2025
6e5a933
Merge remote-tracking branch 'origin/main' into refactor-service-to-ts
jescalada Jun 29, 2025
d5ee52d
chore: add AD type for passport
jescalada Jun 29, 2025
0cfddab
chore: fix linting issues
jescalada Jun 29, 2025
d82f1d1
Merge branch 'refactor-service-to-ts' into refactor-cli-to-ts
jescalada Jun 29, 2025
fde147d
chore: attempt to update test script for CI execution
jescalada Jun 29, 2025
03e2087
chore: update CLI test for CI execution
jescalada Jun 29, 2025
f94147e
chore: attempt to fix linting issues
jescalada Jun 29, 2025
f345d8c
chore: revert tsconfig change and fix failing test
jescalada Jun 29, 2025
5991cad
chore: temporary fix for linting issue
jescalada Jun 29, 2025
916fe60
refactor(ts): convert CLI tests to TS + ESM
jescalada Jul 3, 2025
9304487
refactor(ts): testCliUtilst to TS + ESM
jescalada Jul 3, 2025
cde190f
Merge remote-tracking branch 'origin/main' into refactor-service-to-ts
jescalada Jul 3, 2025
c7ec2e3
chore: fix type errors and clean up
jescalada Jul 3, 2025
6074d31
fix: failing test on empty username
jescalada Jul 3, 2025
f57b1a1
Merge branch 'main' into refactor-service-to-ts
jescalada Jul 3, 2025
d888071
Merge branch 'refactor-service-to-ts' into refactor-cli-to-ts
jescalada Jul 3, 2025
d6d5d95
fix: replace node with tsx and correct filename for CLI test
jescalada Jul 3, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@
"@typescript-eslint/no-explicit-any": "off", // temporary until TS refactor is complete
"@typescript-eslint/no-unused-vars": "off", // temporary until TS refactor is complete
"@typescript-eslint/no-require-imports": "off", // prevents error on old "require" imports
"@typescript-eslint/no-unused-expressions": "off" // prevents error on test "expect" expressions
"@typescript-eslint/no-unused-expressions": "off", // prevents error on test "expect" expressions
"new-cap": "off" // prevents error on express.Router()
},
"settings": {
"react": {
Expand Down
2 changes: 1 addition & 1 deletion index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { hideBin } from 'yargs/helpers';
import * as fs from 'fs';
import { configFile, setConfigFile, validate } from './src/config/file';
import proxy from './src/proxy';
import service from './src/service';
import * as service from './src/service';

const argv = yargs(hideBin(process.argv))
.usage('Usage: $0 [options]')
Expand Down
94 changes: 94 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 7 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"version": "1.18.2",
"description": "Deploy custom push protections and policies on top of Git.",
"scripts": {
"cli": "node ./packages/git-proxy-cli/index.js",
"cli": "tsx ./packages/git-proxy-cli/index.ts",
"client": "vite --config vite.config.js",
"clientinstall": "npm install --prefix client",
"server": "tsx index.ts",
Expand Down Expand Up @@ -89,11 +89,17 @@
"@babel/preset-react": "^7.22.5",
"@commitlint/cli": "^19.0.0",
"@commitlint/config-conventional": "^19.0.0",
"@types/cors": "^2.8.19",
"@types/express": "^5.0.1",
"@types/express-http-proxy": "^1.6.6",
"@types/express-session": "^1.18.2",
"@types/jsonwebtoken": "^9.0.10",
"@types/jwk-to-pem": "^2.0.3",
"@types/lodash": "^4.17.15",
"@types/lusca": "^1.7.5",
"@types/mocha": "^10.0.10",
"@types/node": "^22.13.5",
"@types/passport-local": "^1.0.38",
"@types/yargs": "^17.0.33",
"@typescript-eslint/eslint-plugin": "^8.26.1",
"@typescript-eslint/parser": "^8.26.1",
Expand Down
98 changes: 54 additions & 44 deletions packages/git-proxy-cli/index.js → packages/git-proxy-cli/index.ts
100755 → 100644
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
#!/usr/bin/env node
const axios = require('axios');
const yargs = require('yargs/yargs');
const { hideBin } = require('yargs/helpers');
const fs = require('fs');
const util = require('util');
import axios from 'axios';
import yargs from 'yargs/yargs';
import { hideBin } from 'yargs/helpers';
import fs from 'fs';
import util from 'util';

import { CommitData, PushData, PushFilters } from './types';

const GIT_PROXY_COOKIE_FILE = 'git-proxy-cookie';
// GitProxy UI HOST and PORT (configurable via environment variable)
Expand All @@ -19,7 +21,7 @@ axios.defaults.timeout = 30000;
* @param {string} username The user name to login with
* @param {string} password The password to use for the login
*/
async function login(username, password) {
async function login(username: string, password: string) {
try {
let response = await axios.post(
`${baseUrl}/api/auth/login`,
Expand All @@ -44,7 +46,7 @@ async function login(username, password) {
const user = `"${response.data.username}" <${response.data.email}>`;
const isAdmin = response.data.admin ? ' (admin)' : '';
console.log(`Login ${user}${isAdmin}: OK`);
} catch (error) {
} catch (error: any) {
if (error.response) {
console.error(`Error: Login '${username}': '${error.response.status}'`);
process.exitCode = 1;
Expand Down Expand Up @@ -76,7 +78,7 @@ async function login(username, password) {
* @param {boolean} filters.rejected - If not null, filters for pushes with
* given attribute and status.
*/
async function getGitPushes(filters) {
async function getGitPushes(filters: PushFilters) {
if (!fs.existsSync(GIT_PROXY_COOKIE_FILE)) {
console.error('Error: List: Authentication required');
process.exitCode = 1;
Expand All @@ -91,40 +93,46 @@ async function getGitPushes(filters) {
params: filters,
});

const records = [];
response.data?.forEach((push) => {
const record = {};
record.id = push.id;
record.timestamp = push.timestamp;
record.url = push.url;
record.allowPush = push.allowPush;
record.authorised = push.authorised;
record.blocked = push.blocked;
record.canceled = push.canceled;
record.error = push.error;
record.rejected = push.rejected;

record.lastStep = {
stepName: push.lastStep?.stepName,
error: push.lastStep?.error,
errorMessage: push.lastStep?.errorMessage,
blocked: push.lastStep?.blocked,
blockedMessage: push.lastStep?.blockedMessage,
const records: PushData[] = [];
response.data.forEach((push: PushData) => {
const record: PushData = {
id: push.id,
timestamp: push.timestamp,
url: push.url,
allowPush: push.allowPush,
authorised: push.authorised,
blocked: push.blocked,
canceled: push.canceled,
error: push.error,
rejected: push.rejected,
};

record.commitData = [];
push.commitData?.forEach((pushCommitDataRecord) => {
record.commitData.push({
message: pushCommitDataRecord.message,
committer: pushCommitDataRecord.committer,
if (push.lastStep) {
record.lastStep = {
stepName: push.lastStep?.stepName,
error: push.lastStep?.error,
errorMessage: push.lastStep?.errorMessage,
blocked: push.lastStep?.blocked,
blockedMessage: push.lastStep?.blockedMessage,
};
}

if (push.commitData) {
const commitData: CommitData[] = [];
push.commitData.forEach((pushCommitDataRecord: CommitData) => {
commitData.push({
message: pushCommitDataRecord.message,
committer: pushCommitDataRecord.committer,
});
});
});
record.commitData = commitData;
}

records.push(record);
});

console.log(`${util.inspect(records, false, null, false)}`);
} catch (error) {
} catch (error: any) {
// default error
const errorMessage = `Error: List: '${error.message}'`;
process.exitCode = 2;
Expand All @@ -136,7 +144,7 @@ async function getGitPushes(filters) {
* Authorise git push by ID
* @param {string} id The ID of the git push to authorise
*/
async function authoriseGitPush(id) {
async function authoriseGitPush(id: string) {
if (!fs.existsSync(GIT_PROXY_COOKIE_FILE)) {
console.error('Error: Authorise: Authentication required');
process.exitCode = 1;
Expand Down Expand Up @@ -168,7 +176,7 @@ async function authoriseGitPush(id) {
);

console.log(`Authorise: ID: '${id}': OK`);
} catch (error) {
} catch (error: any) {
// default error
let errorMessage = `Error: Authorise: '${error.message}'`;
process.exitCode = 2;
Expand All @@ -192,7 +200,7 @@ async function authoriseGitPush(id) {
* Reject git push by ID
* @param {string} id The ID of the git push to reject
*/
async function rejectGitPush(id) {
async function rejectGitPush(id: string) {
if (!fs.existsSync(GIT_PROXY_COOKIE_FILE)) {
console.error('Error: Reject: Authentication required');
process.exitCode = 1;
Expand All @@ -215,7 +223,7 @@ async function rejectGitPush(id) {
);

console.log(`Reject: ID: '${id}': OK`);
} catch (error) {
} catch (error: any) {
// default error
let errorMessage = `Error: Reject: '${error.message}'`;
process.exitCode = 2;
Expand All @@ -239,7 +247,7 @@ async function rejectGitPush(id) {
* Cancel git push by ID
* @param {string} id The ID of the git push to cancel
*/
async function cancelGitPush(id) {
async function cancelGitPush(id: string) {
if (!fs.existsSync(GIT_PROXY_COOKIE_FILE)) {
console.error('Error: Cancel: Authentication required');
process.exitCode = 1;
Expand All @@ -262,7 +270,7 @@ async function cancelGitPush(id) {
);

console.log(`Cancel: ID: '${id}': OK`);
} catch (error) {
} catch (error: any) {
// default error
let errorMessage = `Error: Cancel: '${error.message}'`;
process.exitCode = 2;
Expand Down Expand Up @@ -299,7 +307,7 @@ async function logout() {
headers: { Cookie: cookies },
},
);
} catch (error) {
} catch (error: any) {
console.log(`Warning: Logout: '${error.message}'`);
}
}
Expand All @@ -323,7 +331,7 @@ async function reloadConfig() {
await axios.post(`${baseUrl}/api/v1/admin/reload-config`, {}, { headers: { Cookie: cookies } });

console.log('Configuration reloaded successfully');
} catch (error) {
} catch (error: any) {
const errorMessage = `Error: Reload config: '${error.message}'`;
process.exitCode = 2;
console.error(errorMessage);
Expand Down Expand Up @@ -462,8 +470,10 @@ yargs(hideBin(process.argv)) // eslint-disable-line @typescript-eslint/no-unused
})
.command({
command: 'reload-config',
description: 'Reload GitProxy configuration without restarting',
action: reloadConfig,
describe: 'Reload GitProxy configuration without restarting',
handler() {
reloadConfig();
},
})
.demandCommand(1, 'You need at least one command before moving on')
.strict()
Expand Down
Loading
Loading