Skip to content
Merged
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
10 changes: 10 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
.git
.github
.githooks
dist
build
env.secrets
config/agent.yml
*.md
!README.md
scripts
22 changes: 22 additions & 0 deletions .githooks/pre-commit
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#!/usr/bin/env sh
# Same check as fluid-pub/actions go-workload-ci "Verify formatting".
set -e

repo_root="$(git rev-parse --show-toplevel 2>/dev/null)" || {
echo "pre-commit: not inside a Git work tree" >&2
exit 1
}

cd "$repo_root" || exit 1

if ! command -v gofmt >/dev/null 2>&1; then
echo "pre-commit: gofmt not found in PATH" >&2
exit 1
fi

unformatted="$(gofmt -l .)"
if [ -n "$unformatted" ]; then
echo "pre-commit: gofmt would reformat these files (run: gofmt -w .):" >&2
echo "$unformatted" >&2
exit 1
fi
57 changes: 57 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# Dependabot version updates for fluid-pub/agent-gitlab.
version: 2
updates:
- package-ecosystem: gomod
directory: "/"
schedule:
interval: weekly
day: monday
target-branch: develop
assignees:
- "fuse"
reviewers:
- "fuse"
open-pull-requests-limit: 5
commit-message:
prefix: chore(deps)
labels:
- dependencies
- go

- package-ecosystem: docker
directory: "/"
schedule:
interval: weekly
day: monday
target-branch: develop
assignees:
- "fuse"
reviewers:
- "fuse"
open-pull-requests-limit: 5
commit-message:
prefix: chore(deps)
labels:
- dependencies
- docker

- package-ecosystem: github-actions
directory: "/"
schedule:
interval: weekly
day: monday
target-branch: develop
assignees:
- "fuse"
reviewers:
- "fuse"
open-pull-requests-limit: 5
commit-message:
prefix: chore(deps)
labels:
- dependencies
- github-actions
groups:
github-actions:
patterns:
- "*"
19 changes: 19 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
name: CI

on:
pull_request:
push:
branches:
- main
- develop

permissions:
contents: read

jobs:
ci:
uses: fluid-pub/actions/.github/workflows/go-workload-ci.yml@v1
with:
workload_kind: agent
core_repository: fluid-pub/agent-core
core_ref: develop
54 changes: 54 additions & 0 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# CodeQL analysis for Go (aligned with go-workload-ci core checkout layout).
name: CodeQL

on:
push:
branches:
- develop
- main
pull_request:
branches:
- develop
- main
schedule:
- cron: "27 5 * * 1"

permissions:
actions: read
contents: read
security-events: write

jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6

- name: Checkout shared core
uses: actions/checkout@v6
with:
repository: fluid-pub/agent-core
ref: develop
path: core

- name: Align go.mod replace for CI layout
run: |
go mod edit -replace fluid/agents/core=./core
go mod download

- uses: actions/setup-go@v6
with:
go-version: "1.23"
cache-dependency-path: go.sum

- name: Initialize CodeQL
uses: github/codeql-action/init@v4
with:
languages: go

- name: Autobuild
uses: github/codeql-action/autobuild@v4

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v4
21 changes: 21 additions & 0 deletions .github/workflows/release-on-semver-tag.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
name: Release on semver tag

on:
push:
tags:
- "[0-9]+.[0-9]+.[0-9]+"
- "[0-9]+.[0-9]+.[0-9]+-*"

permissions:
contents: write
packages: write

jobs:
release:
uses: fluid-pub/actions/.github/workflows/go-workload-release.yml@v1
with:
workload_kind: agent
binary_name: fluid-agent-gitlab
core_repository: fluid-pub/agent-core
# Pin agent-core until matching semver tags exist for both repos (see agent-core 0.1.1).
core_ref: "0.1.1"
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/build/
/dist/
*.exe
env.secrets
config/agent.yml
6 changes: 6 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Required when this module is the root of fluid-pub/agent-gitlab on GitHub.
# Monorepo dev may use replace => ../core in go.mod without initializing this submodule.
[submodule "core"]
path = core
url = https://github.com/fluid-pub/agent-core.git
branch = develop
20 changes: 20 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Changelog — agent-gitlab

All notable changes to **fluid-pub/agent-gitlab** are documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

Tag naming: `0.y.z` (no `v` prefix). Align `cmd/version.go` and `config/agent.example.yml` (`agent.version`) with the tag before release.

## [Unreleased]

## [0.1.0] - 2026-05-26

### Added

- Initial public release on **agent-core** (WebSocket execution, enrollment, `runtime_config` sync).
- Skills: GitLab API (`create_branch`, `commit_files`, `create_mr`, MR approve/merge/status/assert_merged, `agent.health`) and **`gitlab.repo.checkout_mr`** (local git + optional `run_as` / `chown_repo_to`).
- **`service_credentials`**: `local` (default) or `control_plane` (GitLab token prefetch via control plane after WSS connect).
- CI/CD via `fluid-pub/actions`, container image with **git** for checkout skills, GitHub Release asset `fluid-agent-gitlab-linux-amd64`.
- Local `gofmt` pre-commit hook matching CI.
36 changes: 36 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# syntax=docker/dockerfile:1
# Fluid GitLab execution agent — git and chown required for gitlab.repo.checkout_mr.

FROM golang:1.26-bookworm AS build

ARG BINARY_NAME=fluid-agent-gitlab
ARG VERSION=0.0.0
ARG TARGETOS=linux
ARG TARGETARCH=amd64

WORKDIR /src

COPY go.mod go.sum ./
COPY core ./core
COPY cmd ./cmd
COPY internal ./internal

RUN go mod download

RUN CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} \
go build -ldflags "-s -w -X main.Version=${VERSION}" \
-o /out/workload ./cmd

FROM debian:bookworm-slim

RUN apt-get update \
&& apt-get install -y --no-install-recommends ca-certificates git \
&& rm -rf /var/lib/apt/lists/*

COPY --from=build /out/workload /usr/local/bin/workload

# checkout_mr may use chown; typical deployment runs this agent with host workspace mounts.
USER root

ENTRYPOINT ["/usr/local/bin/workload"]
CMD ["-config", "/etc/fluid/config/config.yaml"]
40 changes: 40 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
GO ?= go
CONFIG ?= config/agent.yml
BINARY ?= dist/fluid-agent-gitlab
VERSION ?= 0.1.0
LDFLAGS := -ldflags "-s -w -X main.Version=$(VERSION)"

.PHONY: deps dev build build-linux test fmt lint help monorepo-replace

monorepo-replace:
$(GO) mod edit -replace fluid/agents/core=../core
@$(GO) mod tidy

deps:
@test -d core || test -d ../core || (echo "Run: git submodule update --init --recursive (public repo) or develop from fluid monorepo with ../core" && exit 1)
$(GO) mod download
@$(GO) mod tidy

dev: deps
@test -f env.secrets || (echo "Missing env.secrets. Create it from env.secrets.example." && exit 1)
@set -a; . ./env.secrets; set +a; $(GO) run ./cmd -config $(CONFIG)

build: deps
$(GO) build ./...

build-linux: deps
@mkdir -p dist
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 $(GO) build $(LDFLAGS) -o $(BINARY) ./cmd

test: deps
$(GO) test ./...

fmt:
gofmt -w .
$(GO) fmt ./...

lint:
@echo "No linter configured for this module yet."

help:
@echo "Targets: deps dev build build-linux test fmt monorepo-replace"
85 changes: 83 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,83 @@
# agent-gitlab
Fluid GitLab agent
# fluid-pub/agent-gitlab

Fluid **execution agent** for **GitLab**: maintains a **persistent WSS** connection to the control plane (`/v1/agents/websocket`) for skills, logs, and `runtime_config` sync. GitLab REST API skills and **`gitlab.repo.checkout_mr`** (local **git**) run in this agent — not on the Linux interface agent.

## Repository layout

| Path | Role |
|------|------|
| `core/` | Git submodule → [`fluid-pub/agent-core`](https://github.com/fluid-pub/agent-core) |
| `cmd/` | Entrypoint and `cmd/version.go` (semver for releases) |
| `internal/` | GitLab API client, agent skills, config |
| `config/agent.example.yml` | Configuration template |
| `.github/workflows/` | CI and release via [`fluid-pub/actions`](https://github.com/fluid-pub/actions) |

## Local development

One-time per clone, enable the same **`gofmt`** check as CI:

```bash
./scripts/install-git-hooks.sh
```

```bash
git submodule update --init --recursive
cp config/agent.example.yml config/agent.yml
cp env.secrets.example env.secrets
# Set GITLAB_* and FLUID_CONTROLPLANE_* in env.secrets (never commit that file).
source env.secrets
make dev
```

`make dev` runs `go run ./cmd` with `-config config/agent.yml`.

**Monorepo Fluid** (`code/agents/gitlab/`): use `make monorepo-replace` so `go.mod` points at `../core` instead of the `core/` submodule. Do not commit that replace on `develop` (CI and releases use `replace => ./core`).

### Git in the Fluid workspace

```bash
cd code/agents/gitlab
git remote add origin git@github.com:fluid-pub/agent-gitlab.git # if needed
git fetch origin
git checkout -B develop origin/develop
git submodule update --init --recursive
./scripts/install-git-hooks.sh
make monorepo-replace # optional when using code/agents/core in the monorepo
```

Keep `env.secrets` and `config/agent.yml` local (gitignored).

## Control plane connection

| Phase | Transport | Purpose |
|-------|-----------|---------|
| Steady state | **WSS** (`controlplane.websocket_url`) | `skill_invoke` / `skill_result`, log events, `runtime_config` push |
| First boot only (optional) | HTTP `POST /api/v1/enrollment/enroll` | Exchange `FLUID_ENROLLMENT_TOKEN` for `organization_uuid` + connection token |

Durable credentials: `/etc/fluid/gitlab/credentials.yaml` (`-credentials` flag). Enroll with `agent_type: gitlab`, `principal: execution_agent`.

### Service credentials

- **`local`** (default): GitLab token from config / env / `FLUID_SERVICE_CREDENTIALS_ENV_FILE`.
- **`control_plane`**: after WSS connect, prefetch GitLab token from the control plane (requires `use_case_run_id` in enrollment extra args or `FLUID_USE_CASE_RUN_ID`).

## Container image

The published image includes **`git`** (and runs as **root**) so **`gitlab.repo.checkout_mr`** can clone under `/tmp/fluid/` workspaces. API-only deployments may still use the same image.

## Releases

Push a semver tag **without** `v` (e.g. `0.1.0`) matching `var Version` in `cmd/version.go`. The release workflow publishes:

- `ghcr.io/fluid-pub/agent-gitlab:<tag>`
- GitHub Release asset `fluid-agent-gitlab-linux-amd64` and `SHA256SUMS.txt`

Release builds pin **`agent-core`** to the **same semver tag** when `core_ref` is empty in the workflow (see `.github/workflows/release-on-semver-tag.yml`).

## Changelog

Release notes: [CHANGELOG.md](CHANGELOG.md).

## Security

See [SECURITY.md](SECURITY.md) for vulnerability reporting. Repository automation includes Dependabot and CodeQL.
Loading
Loading