Compare commits

..
Author SHA1 Message Date
David Rotermund 010024e625 Missing git-bridge build files 2026-10-22 02:28:58 +02:00
6 changed files with 149 additions and 96 deletions
+1 -8
View File
@@ -21,14 +21,7 @@ server {
proxy_send_timeout 10m;
}
# Only the git smart-HTTP endpoints of a project (/git/<project id>[.git]/...) are
# public. git-bridge's other routes (/status, /health_check, /metrics, /diags,
# /api/...) are meant for the internal network only and must not be reachable.
location /git/ {
return 404;
}
location ~ "^/git/[0-9a-f]{24}(\.git)?(/|$)" {
location ^~ /git/ {
resolver_timeout 2s;
resolver 127.0.0.11 valid=10s;
set $git_upstream http://${GIT_BRIDGE_HOST}:${GIT_BRIDGE_PORT};
+54
View File
@@ -0,0 +1,54 @@
# Build the a8m/envsubst binary, as it supports default values,
# which the gnu envsubst (from gettext-base) does not.
FROM golang:1.25.5-alpine AS envsubst_builder
WORKDIR /build
RUN go install github.com/a8m/envsubst/cmd/envsubst@latest
FROM maven:3-amazoncorretto-21-debian AS base
RUN apt-get update && apt-get install -y make git sqlite3 curl \
&& rm -rf /var/lib/apt/lists
COPY --from=envsubst_builder /go/bin/envsubst /opt/envsubst
RUN chmod +x /opt/envsubst
RUN useradd --create-home node
FROM base AS builder
COPY . /app
WORKDIR /app
RUN make package \
# The name of the created jar contains the current version tag.
# Rename it to a static path that can be used for copying.
&& find /app/target \
-name 'writelatex-git-bridge*jar-with-dependencies.jar' \
-exec mv {} /git-bridge.jar \;
FROM amazoncorretto:21-alpine
RUN apk add --update --no-cache bash git sqlite procps htop net-tools jemalloc util-linux
ENV LD_PRELOAD=/usr/lib/libjemalloc.so.2
RUN adduser -D node
COPY --from=builder /git-bridge.jar /
COPY --from=envsubst_builder /go/bin/envsubst /opt/envsubst
RUN chmod +x /opt/envsubst
COPY conf/envsubst_template.json envsubst_template.json
COPY start.sh start.sh
COPY server-pro-start.sh server-pro-start.sh
RUN mkdir conf
RUN chown node:node conf
USER node
CMD ["/start.sh"]
+89
View File
@@ -0,0 +1,89 @@
# git-bridge makefile
MVN_OPTS := --no-transfer-progress
MVN_TARGET := target/writelatex-git-bridge-1.0-SNAPSHOT-jar-with-dependencies.jar
export BUILD_NUMBER ?= local
export BRANCH_NAME ?= $(shell git rev-parse --abbrev-ref HEAD)
BRANCH_NAME_TAG_SAFE = $(shell echo $(BRANCH_NAME) | sed 's/\//\-\-/g')
export COMMIT_SHA ?= $(shell git rev-parse HEAD)
PROJECT_NAME = git-bridge
IMAGE_CI ?= ci/$(PROJECT_NAME):$(BRANCH_NAME_TAG_SAFE)-$(BUILD_NUMBER)
IMAGE_REPO ?= us-east1-docker.pkg.dev/overleaf-ops/ol-docker/$(PROJECT_NAME)
IMAGE_REPO_BRANCH ?= $(IMAGE_REPO):$(BRANCH_NAME_TAG_SAFE)
IMAGE_REPO_MAIN ?= $(IMAGE_REPO):main
IMAGE_REPO_FINAL ?= $(IMAGE_REPO_BRANCH)-$(BUILD_NUMBER)
runtime-conf:
/opt/envsubst < conf/envsubst_template.json > conf/runtime.json
run: $(MVN_TARGET) runtime-conf
@exec java $(GIT_BRIDGE_JVM_ARGS) -jar $(MVN_TARGET) conf/runtime.json
$(MVN_TARGET): $(shell find src -type f) pom.xml
mvn $(MVN_OPTS) package -DskipTests
build: $(MVN_TARGET)
docker_build_base:
docker build --pull \
--build-arg BUILDKIT_INLINE_CACHE=1 \
--cache-from $(IMAGE_REPO_BRANCH) \
--cache-from $(IMAGE_REPO_MAIN) \
--tag $(IMAGE_CI) \
--target base \
.
docker_build:
docker build --pull \
--build-arg BUILDKIT_INLINE_CACHE=1 \
--cache-from $(IMAGE_REPO_BRANCH) \
--cache-from $(IMAGE_REPO_MAIN) \
--tag $(IMAGE_REPO_BRANCH) \
--tag $(IMAGE_REPO_FINAL) \
.
format:
mvn $(MVN_OPTS) com.spotify.fmt:fmt-maven-plugin:check
docker_format:
docker run --rm -v $(PWD):$(PWD) -w $(PWD) --user node $(IMAGE_CI) make format
format_fix:
mvn $(MVN_OPTS) com.spotify.fmt:fmt-maven-plugin:format
test:
mvn $(MVN_OPTS) test
docker_test:
docker run --rm -v $(PWD):$(PWD) -w $(PWD) --user node $(IMAGE_CI) make test
clean:
mvn $(MVN_OPTS) clean
package: clean
mvn $(MVN_OPTS) package -DskipTests
refresh_cache: refresh_cache_branch
refresh_cache_branch:
docker inspect $(IMAGE_REPO_BRANCH) > /dev/null && docker pull $(IMAGE_REPO_BRANCH) || true
refresh_cache: refresh_cache_latest
refresh_cache_latest:
docker inspect $(IMAGE_REPO_MAIN) > /dev/null && docker pull $(IMAGE_REPO_MAIN) || true
push:
docker push $(IMAGE_REPO_FINAL)
push_branch:
docker push $(IMAGE_REPO_BRANCH)
clean_ci:
-docker rmi -f $(IMAGE_CI) $(IMAGE_REPO_FINAL)
-git clean -xdf .
.PHONY: run package build clean test runtime-conf
@@ -101,14 +101,14 @@ const GitBridgePATManager = {
if (!objToken?.user_id) return null
// does the user still exists, not deleted and not suspended?
// does the user still exists and not deleted?
// tokens of a deleted user are not deleted until user expires
const user = await db.users.findOne(
{ _id: new ObjectId(objToken.user_id) },
{ projection: { _id: 1, suspended: 1 } }
{ projection: { _id: 1 } }
)
if (!user || user.suspended) return null
if (!user) return null
// non-blocking
db.oauthAccessTokens.updateOne(
@@ -37,11 +37,8 @@ const TrackChangesController = {
async getAllRanges(req, res, next) {
try {
const { project_id } = req.params
// document-updater only knows the docs loaded in Redis. Flush them to
// docstore (without unloading) and read every non-deleted doc from there.
await DocumentUpdaterHandler.promises.flushProjectToMongo(project_id)
const docs = await DocstoreManager.promises.getAllRanges(project_id)
res.json(docs.map(doc => ({ id: doc._id, ranges: doc.ranges ?? {} })))
const ranges = await DocumentUpdaterHandler.promises.getProjectRanges(project_id)
res.json(ranges)
} catch (err) {
next(err)
}
@@ -53,9 +50,6 @@ const TrackChangesController = {
// provided here to assign names to authors who have left the project but still have unaccepted changes.
try {
const { project_id } = req.params
// Same as getAllRanges: a tracked change still in document-updater is
// not in docstore yet, so its author would be missing here.
await DocumentUpdaterHandler.promises.flushProjectToMongo(project_id)
const memberIds = await DocstoreManager.promises.getTrackedChangesUserIds(project_id)
const limit = pLimit(3)
const users = await Promise.all(
@@ -1,77 +0,0 @@
import { batchedUpdate } from '@overleaf/mongo-utils/batchedUpdate.js'
import { promiseMapWithLimit } from '@overleaf/promise-utils'
import { db } from './lib/mongodb.mjs'
const tags = ['server-ce', 'server-pro']
const WRITE_CONCURRENCY = parseInt(process.env.WRITE_CONCURRENCY, 10) || 10
// The Zotero module used to store linkedFileData with its own key names.
// "Zotero: fix for 6.3.0" switched to the names accepted by the
// overleaf-editor-core schema, but files imported before that still carry the
// old keys, which document-updater rejects (e.g. when cloning the project).
const LEGACY_KEYS = [
'zoteroGroupId',
'importedByUserId',
'importedByName',
'bibFormat',
]
function hasLegacyKeys(data) {
return (
data?.provider === 'zotero' && LEGACY_KEYS.some(key => key in data)
)
}
function convert(data) {
const importerId = data.importer_id ?? data.importedByUserId
const format = data.format ?? data.bibFormat
return {
provider: 'zotero',
group_id: data.group_id ?? data.zoteroGroupId ?? null,
...(data.importedAt && { importedAt: data.importedAt }),
...(importerId && { importer_id: importerId.toString() }),
importer_name: data.importer_name ?? data.importedByName ?? 'Unknown',
format: format === 'biblatex' ? 'biblatex' : 'bibtex',
}
}
function collectUpdates(folder, mongoPath, updates) {
if (!folder) return
;(folder.fileRefs || []).forEach((file, i) => {
if (hasLegacyKeys(file?.linkedFileData)) {
updates[`${mongoPath}.fileRefs.${i}.linkedFileData`] = convert(
file.linkedFileData
)
}
})
;(folder.folders || []).forEach((subfolder, i) => {
collectUpdates(subfolder, `${mongoPath}.folders.${i}`, updates)
})
}
const migrate = async () => {
await batchedUpdate(
db.projects,
{},
async nextBatch => {
await promiseMapWithLimit(WRITE_CONCURRENCY, nextBatch, async project => {
const updates = {}
;(project.rootFolder || []).forEach((folder, i) => {
collectUpdates(folder, `rootFolder.${i}`, updates)
})
if (Object.keys(updates).length === 0) return
await db.projects.updateOne({ _id: project._id }, { $set: updates })
})
},
{ _id: 1, rootFolder: 1 }
)
}
const rollback = async () => {}
export default {
tags,
migrate,
rollback,
}