Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 3 additions & 2 deletions .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,10 @@
},
"parser": "espree",
"env": {
"cypress/globals": true
"browser": true,
"node": true,
"mocha": true
},
"plugins": ["cypress"],
"rules": {
"@typescript-eslint/no-unused-expressions": "off"
}
Expand Down
7 changes: 5 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,10 @@ jobs:
- name: Run cypress test
uses: cypress-io/github-action@b8ba51a856ba5f4c15cf39007636d4ab04f23e3c # v6.10.2
with:
start: npm start &
wait-on: 'http://localhost:3000'
start: npm run start:ci
wait-on: 'http://localhost:8080'
wait-on-timeout: 120
run: npm run cypress:run
env:
NODE_ENV: test
CYPRESS_BASE_URL: 'http://localhost:8080'
68 changes: 68 additions & 0 deletions .github/workflows/e2e.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
name: E2E Tests

permissions:
contents: read
issues: write
pull-requests: write

on:
push:
branches: [main]
issue_comment:
types: [created]

jobs:
e2e:
runs-on: ubuntu-latest
# Run on push/PR or when a maintainer comments "/test e2e" or "/run e2e"
if: |
github.event_name != 'issue_comment' || (
github.event.issue.pull_request &&
(contains(github.event.comment.body, '/test e2e') || contains(github.event.comment.body, '/run e2e')) &&
(github.event.comment.author_association == 'OWNER' ||
github.event.comment.author_association == 'MEMBER' ||
github.event.comment.author_association == 'COLLABORATOR')
)

steps:
- name: Checkout code
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4
with:
# When triggered by comment, checkout the PR branch
ref: ${{ github.event_name == 'issue_comment' && format('refs/pull/{0}/head', github.event.issue.number) || github.ref }}

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435

- name: Set up Docker Compose
uses: docker/setup-compose-action@364cc21a5de5b1ee4a7f5f9d3fa374ce0ccde746

- name: Set up Node.js
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version: '20'
cache: 'npm'

- name: Install dependencies
run: npm ci

- name: Configure Git for CI
run: |
git config --global user.name "CI Runner"
git config --global user.email "ci@example.com"
git config --global init.defaultBranch main

- name: Build and start services with Docker Compose
run: docker compose up -d --build

- name: Wait for services to be ready
run: |
timeout 60 bash -c 'until docker compose ps | grep -q "Up"; do sleep 2; done'
sleep 10

- name: Run E2E tests
run: npm run test:e2e

- name: Stop services
if: always()
run: docker compose down -v
54 changes: 54 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# Build stage
FROM node:20 AS builder

USER root

WORKDIR /app

# Copy package files
COPY package*.json ./

# Install all dependencies (including dev dependencies for building)
RUN npm pkg delete scripts.prepare && npm ci --include=dev

# Copy source files and config files needed for build
COPY tsconfig.json tsconfig.publish.json proxy.config.json config.schema.json integration-test.config.json vite.config.ts index.html index.ts ./
COPY src/ /app/src/
COPY public/ /app/public/

# Build the UI and server
RUN npm run build-ui \
&& npx tsc --project tsconfig.publish.json \
&& cp config.schema.json dist/

# Prune dev dependencies after build is complete
RUN npm prune --omit=dev

# Production stage
FROM node:20-slim AS production

RUN apt-get update && apt-get install -y \
git tini \
&& rm -rf /var/lib/apt/lists/*

WORKDIR /app

# Copy the modified package.json (without prepare script) and production node_modules from builder
COPY --from=builder /app/package*.json ./
COPY --from=builder /app/node_modules/ /app/node_modules/

# Copy built artifacts from builder stage
COPY --from=builder /app/dist/ /app/dist/
COPY --from=builder /app/build /app/dist/build/

# Copy configuration files needed at runtime
COPY proxy.config.json config.schema.json ./

# Copy entrypoint script
COPY docker-entrypoint.sh /docker-entrypoint.sh
RUN chmod +x /docker-entrypoint.sh

EXPOSE 8080 8000

ENTRYPOINT ["tini", "--", "/docker-entrypoint.sh"]
CMD ["node", "dist/index.js"]
2 changes: 1 addition & 1 deletion cypress.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ const { defineConfig } = require('cypress');

module.exports = defineConfig({
e2e: {
baseUrl: process.env.CYPRESS_BASE_URL || 'http://localhost:3000',
baseUrl: process.env.CYPRESS_BASE_URL || 'http://localhost:8080',
chromeWebSecurity: false, // Required for OIDC testing
setupNodeEvents(on, config) {
on('task', {
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
45 changes: 45 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
services:
git-proxy:
build: .
ports:
- '8000:8000'
- '8081:8081'
command: ['node', 'dist/index.js', '--config', '/app/integration-test.config.json']
volumes:
- ./integration-test.config.json:/app/integration-test.config.json:ro
depends_on:
- mongodb
- git-server
networks:
- git-network
environment:
- NODE_ENV=test
- GIT_PROXY_UI_PORT=8081
- GIT_PROXY_SERVER_PORT=8000
- NODE_OPTIONS=--trace-warnings

mongodb:
image: mongo:7
ports:
- '27017:27017'
networks:
- git-network
environment:
- MONGO_INITDB_DATABASE=gitproxy
volumes:
- mongodb_data:/data/db

git-server:
build: localgit/
environment:
- GIT_HTTP_EXPORT_ALL=true
networks:
- git-network
hostname: git-server

networks:
git-network:
driver: bridge

volumes:
mongodb_data:
19 changes: 19 additions & 0 deletions docker-entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#!/bin/bash

# Create runtime configuration file for the UI
# This allows the UI to discover its environment dynamically
cat > /app/dist/runtime-config.json << EOF
{
"apiUrl": "${VITE_API_URI:-}",
"allowedOrigins": [
"${VITE_ALLOWED_ORIGINS:-*}"
],
"environment": "${NODE_ENV:-production}"
}
EOF

echo "Created runtime configuration with:"
echo " API URL: ${VITE_API_URI:-auto-detect}"
echo " Allowed Origins: ${VITE_ALLOWED_ORIGINS:-*}"

exec "$@"
50 changes: 50 additions & 0 deletions integration-test.config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
{
"cookieSecret": "integration-test-cookie-secret",
"sessionMaxAgeHours": 12,
"rateLimit": {
"windowMs": 60000,
"limit": 150
},
"tempPassword": {
"sendEmail": false,
"emailConfig": {}
},
"authorisedList": [
{
"project": "coopernetes",
"name": "test-repo",
"url": "http://git-server:8080/coopernetes/test-repo.git"
},
{
"project": "finos",
"name": "git-proxy",
"url": "http://git-server:8080/finos/git-proxy.git"
}
],
"sink": [
{
"type": "fs",
"params": {
"filepath": "./."
},
"enabled": false
},
{
"type": "mongo",
"connectionString": "mongodb://mongodb:27017/gitproxy",
"options": {
"useNewUrlParser": true,
"useUnifiedTopology": true,
"tlsAllowInvalidCertificates": false,
"ssl": false
},
"enabled": true
}
],
"authentication": [
{
"type": "local",
"enabled": true
}
]
}
20 changes: 20 additions & 0 deletions localgit/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
FROM httpd:2.4

RUN apt-get update && apt-get install -y \
git \
apache2-utils \
&& rm -rf /var/lib/apt/lists/*

COPY httpd.conf /usr/local/apache2/conf/httpd.conf

RUN htpasswd -cb /usr/local/apache2/conf/.htpasswd admin admin123 \
&& htpasswd -b /usr/local/apache2/conf/.htpasswd testuser user123

COPY init-repos.sh /usr/local/bin/init-repos.sh

RUN chmod +x /usr/local/bin/init-repos.sh \
&& /usr/local/bin/init-repos.sh

EXPOSE 8080

CMD ["httpd-foreground"]
48 changes: 48 additions & 0 deletions localgit/httpd.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
ServerRoot "/usr/local/apache2"
Listen 0.0.0.0:8080

LoadModule mpm_event_module modules/mod_mpm_event.so
LoadModule unixd_module modules/mod_unixd.so
LoadModule authz_core_module modules/mod_authz_core.so
LoadModule authn_core_module modules/mod_authn_core.so
LoadModule auth_basic_module modules/mod_auth_basic.so
LoadModule authn_file_module modules/mod_authn_file.so
LoadModule authz_user_module modules/mod_authz_user.so
LoadModule alias_module modules/mod_alias.so
LoadModule cgi_module modules/mod_cgi.so
LoadModule env_module modules/mod_env.so
LoadModule dir_module modules/mod_dir.so
LoadModule mime_module modules/mod_mime.so
LoadModule log_config_module modules/mod_log_config.so

User www-data
Group www-data

ServerName git-server

# Git HTTP Backend Configuration - Serve directly from root
ScriptAlias / "/usr/lib/git-core/git-http-backend/"
SetEnv GIT_PROJECT_ROOT "/var/git"
SetEnv GIT_HTTP_EXPORT_ALL

<LocationMatch "^/.+\.git">
AuthType Basic
AuthName "Git Access"
AuthUserFile "/usr/local/apache2/conf/.htpasswd"
Require valid-user
</LocationMatch>

# Error and access logging
ErrorLog /proc/self/fd/2
LogLevel info

# Define log formats
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
LogFormat "%h %l %u %t \"%r\" %>s %b" common
LogFormat "%{Referer}i -> %U" referer
LogFormat "%{User-agent}i" agent

# Use combined format for detailed request logging
CustomLog /proc/self/fd/1 combined

TypesConfig conf/mime.types
Loading
Loading