Skip to content

Commit 53173e5

Browse files
authored
Promote Drift to CE (#2334)
* Agent task for moving drift from EE to CE * Add CE drift module * Update Dockerfile for CE drift * Fix Dockerfile warnings * Decouple EE backend from EE drift * Add impl note on switching EE backend from drift/middleware to backend/middleware * Switch ee/drift to a thin CE wrapper * Update docs; discover ee/cli dependency * Add Step 7 - Promote GitHub Issues notifier to CE * Promote GitHub Issues Drift Notifier to CE * Revert to using drift middleware in ee github controller * Fix ee/backend test by switching middleware back to backend * Add final notes to impl plan * Rename provider.go for consistency
1 parent 4e9676a commit 53173e5

File tree

32 files changed

+3394
-196
lines changed

32 files changed

+3394
-196
lines changed

Dockerfile_drift

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM golang:1.24.0 as builder
1+
FROM golang:1.24.0 AS builder
22
ARG COMMIT_SHA
33
RUN echo "commit sha: ${COMMIT_SHA}"
44

@@ -16,11 +16,11 @@ RUN go version
1616
# https://github.com/ethereum/go-ethereum/issues/2738
1717
# Build static binary "-getmode=vendor" does not work with go-ethereum
1818

19-
RUN go build -ldflags="-X 'main.Version=${COMMIT_SHA}'" -o drift_exe ./ee/drift/
19+
RUN go build -ldflags="-X 'main.Version=${COMMIT_SHA}'" -o drift_exe ./drift/
2020

2121
# Multi-stage build will just copy the binary to an alpine image.
22-
FROM ubuntu:24.04 as runner
23-
ENV ATLAS_VERSION v0.31.0
22+
FROM ubuntu:24.04 AS runner
23+
ENV ATLAS_VERSION=v0.31.0
2424
ARG COMMIT_SHA
2525
WORKDIR /app
2626

@@ -42,8 +42,7 @@ EXPOSE 3000
4242

4343
# Copy the binary to the corresponding folder
4444
COPY --from=builder /go/src/github.com/diggerhq/digger/drift_exe /app/driftapp
45-
COPY --from=builder /go/src/github.com/diggerhq/digger/ee/drift/scripts/entrypoint.sh /app/entrypoint.sh
46-
ADD ee/backend/templates ./templates
45+
COPY --from=builder /go/src/github.com/diggerhq/digger/drift/scripts/entrypoint.sh /app/entrypoint.sh
4746

4847
# Run the binary
4948
ENTRYPOINT ["/bin/bash", "/app/entrypoint.sh"]

agent-tasks/promote-drift-ee-ce.md

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
# Promote Drift from EE to CE
2+
3+
- Target: CE availability, separate service under `drift/`
4+
- Related: `ee/drift` (source), `backend` (models/middleware), `libs`
5+
6+
## Goal
7+
Make drift functionality available in Community Edition by moving the existing EE drift service out of `ee/` and into top-level CE, with minimal disruption to existing deployments.
8+
9+
## Non-Goals
10+
- Redesign of feature behavior or APIs.
11+
- Merging the drift service into the monolithic `backend` app (can be a later refactor).
12+
- Moving EE-only CLI features (advanced Slack aggregation) to CE.
13+
14+
## Approach
15+
- Keep drift as a standalone CE service at `drift/` (new module). Alternative would be to merge drift endpoints into CE backend but we want to keep potential breaking changes to a minimum.
16+
17+
## Current State Summary
18+
- `ee/drift` is a Go module that depends on CE code: `backend/models`, `backend/utils`, `backend/ci_backends`, and `libs` packages. It exposes:
19+
- `/_internal/process_drift`
20+
- `/_internal/process_drift_for_org`
21+
- `/_internal/trigger_drift_for_project`
22+
- `/_internal/process_notifications`
23+
- Slack test/real notification endpoints
24+
- DB models already include drift fields in CE (`backend/models/orgs.go`, `Project`, `Organisation`). No migrations required.
25+
- `ee/backend` imports `ee/drift/middleware` only for context keys; CE already defines these keys in `backend/middleware`.
26+
- Build: `Dockerfile_drift` builds `./ee/drift` and copies `ee/backend/templates` (templates unused by drift).
27+
- Workspace: `go.work` includes `./ee/drift`.
28+
29+
30+
## Acceptance Criteria
31+
- Code builds:
32+
- `go build ./drift`, `go build ./backend`, `go build ./ee/backend` succeed.
33+
- No imports from `ee/drift` remain in CE modules.
34+
- `go.work` references `./drift`; `./ee/drift` remains as a wrapper module present in workspace.
35+
- Drift endpoints respond 200 with correct auth and perform expected side effects (project drift job creation and notifications).
36+
- `ee/backend` uses `backend/middleware` for context keys and builds without `ee/drift` dependency.
37+
- `Dockerfile_drift` successfully builds and runs the CE drift service.
38+
- EE wrapper builds and runs: `go build ./ee/drift` and boot equivalently to CE.
39+
40+
## Risks & Mitigations
41+
- Import drift: Missed references → repo-wide search and CI builds on all modules.
42+
- Auth mismatch: Align on `InternalApiAuth` or accept both secrets to avoid outages.
43+
- Duplicate GitHub client: Remove only after ensuring CE utils cover all use cases.
44+
45+
46+
## Follow-ups (Later; not in this plan)
47+
- Provide a dedicated EE wrapper image (`Dockerfile_drift_ee`) if distribution needs it.
48+
- Consolidate middleware/utils and remove duplicates once parity is verified.
49+
- Remove duplicate GitHub client from drift utils after verifying CE `backend/utils` covers all use-cases.
50+
- Consider merging drift into CE `backend` later to reduce services.
51+
- Promote EE advanced Slack aggregator to CE, or document as EE-only.
52+
- Unify on a single internal secret (`DIGGER_INTERNAL_SECRET`) and deprecate `DIGGER_WEBHOOK_SECRET`.
53+
54+
## Commit-by-Commit Execution Plan
55+
56+
1) Add CE drift module
57+
- Action: Copy `ee/drift` to `drift/`. Update `drift/go.mod` module path to `github.com/diggerhq/digger/drift`; keep `replace` entries to `../libs` and `../backend`. Update internal self-imports from `github.com/diggerhq/digger/ee/drift/...` to `github.com/diggerhq/digger/drift/...`.
58+
- Files: `drift/**` (new), `drift/go.mod`, `drift/go.sum`.
59+
- Verify: `go build ./drift` compiles.
60+
61+
2) Update Dockerfile for CE drift
62+
- Action: Point `Dockerfile_drift` build target to `./drift`, copy entrypoint from `drift/scripts/entrypoint.sh`, and drop copying `ee/backend/templates` (not used).
63+
- Files: `Dockerfile_drift`.
64+
- Verify: `docker build -f Dockerfile_drift .` reaches build of `./drift` (local build or CI).
65+
66+
3) Add CE drift to workspace
67+
- Action: Add `./drift` to `go.work` (keep `./ee/drift` for now; wrapper will replace it later). Run `go work sync` if applicable.
68+
- Files: `go.work`.
69+
- Verify: `go list` resolves `./drift` module in workspace.
70+
71+
4) Decouple EE backend from EE drift
72+
- Action: In `ee/backend`, replace imports of `github.com/diggerhq/digger/ee/drift/middleware` with `github.com/diggerhq/digger/backend/middleware`. Remove `github.com/diggerhq/digger/ee/drift` requirement from `ee/backend/go.mod` and run `go mod tidy`.
73+
- Files: `ee/backend/controllers/**`, `ee/backend/go.mod`, `ee/backend/go.sum`.
74+
- Verify: `go build ./ee/backend` compiles without `ee/drift` dependency.
75+
76+
5) Add EE wrapper (tiny main)
77+
- Action: Replace existing `ee/drift` implementation with a minimal `main.go` that mirrors CE drift startup but imports CE packages from `github.com/diggerhq/digger/drift/...`. Update `ee/drift/go.mod` to depend on CE drift module; remove old `controllers/`, `middleware/`, `services/`, `utils/`, `scripts/` (except keep any wrapper-specific entrypoint if needed).
78+
- Files: `ee/drift/main.go` (new), `ee/drift/go.mod` (updated), remove old `ee/drift/**` dirs.
79+
- Verify: `go build ./ee/drift` compiles and starts with same endpoints.
80+
81+
6) Documentation updates
82+
- Action: Update docs to note drift is CE; list env vars; note EE wrapper intent and parity.
83+
- Files: `README.md` (or relevant docs), `agent-tasks/promote-drift-ee-ce.md` (mark steps done as they land).
84+
- Verify: Docs render and link paths are valid.
85+
86+
7) Promote GitHub Issues notifier to CE
87+
- Action: Remove EE dependency for Issues notifications by promoting the Issues notifier into CE.
88+
- Add CE implementation: `cli/pkg/drift/github_issue.go` (copy/adapt from `ee/cli/pkg/drift/github_issue.go`).
89+
- Extend CE provider `cli/pkg/drift/Provider.go` to honor `INPUT_DRIFT_GITHUB_ISSUES` and return the CE `GithubIssueNotification` when set.
90+
- Keep Slack path unchanged; no changes to EE advanced Slack aggregation.
91+
- Update docs workflow to remove `ee: 'true'` requirement for GitHub Issues notifications.
92+
- Files: `cli/pkg/drift/Provider.go`, `cli/pkg/drift/github_issue.go`, `docs/ce/features/drift-detection.mdx`.
93+
- Verify:
94+
- `go build ./cli` succeeds.
95+
- Running with `INPUT_DRIFT_GITHUB_ISSUES='true'` uses CE notifier (no EE required).
96+
- Docs reflect CE-only workflow (no `ee: 'true'`).
97+
98+
## Verification Steps (per commit, non-code)
99+
- Build touched modules: `go build ./drift`, `go build ./backend`, `go build ./ee/backend`, `go build ./ee/drift` (after step 5).
100+
- Smoke tests for drift endpoints via curl with proper auth headers.
101+
- CI passes for modules affected in each commit.
102+
103+
## Implementation Notes
104+
105+
Q: Functionality-wise, how is drift middleware different from backend middleware? Should we prefer using CE drift middleware (copy of EE) for safety?
106+
107+
A:
108+
- Constants parity: Both expose the same context keys (`ORGANISATION_ID_KEY="organisation_ID"`, `ACCESS_LEVEL_KEY="access_level"`). EE backend only needed these keys, so switching to `backend/middleware` is safe.
109+
- Webhook auth:
110+
- Drift’s `WebhookAuth()` validates `DIGGER_WEBHOOK_SECRET` and reads optional `X-Digger-Org-ID`.
111+
- Backend’s `InternalApiAuth()` validates `DIGGER_INTERNAL_SECRET` and also supports `X-Digger-Org-ID`.
112+
- EE backend wasn’t using drift’s webhook auth; only constants, so no behavior change.
113+
- Job token auth:
114+
- Drift’s `JobTokenAuth()` accepts `cli:` tokens and sets org/access level.
115+
- Backend’s `JWTBearerTokenAuth()` and `NoopApiAuth()` already handle `cli:` tokens (and also API `t:` tokens and JWTs) with the same org/access-level semantics.
116+
- EE backend doesn’t depend on drift’s job token middleware.
117+
- Integration boundary: Backend and drift integrate via shared DB (`backend/models`) and external calls; backend doesn’t call drift endpoints today.
118+
- If closer drift parity is desired later, import CE drift middleware in relevant services or add a backend wrapper that accepts both `DIGGER_WEBHOOK_SECRET` and `DIGGER_INTERNAL_SECRET`.
119+
120+
New finding: EE CLI required for GitHub Issues notifications (new step 7)
121+
- Observation: The GitHub Issues notification path for drift currently lives in the EE CLI (`ee/cli/pkg/drift/provider.go` and related), selected via `INPUT_DRIFT_GITHUB_ISSUES`. Our Action also toggles EE CLI usage via `ee: 'true'`.
122+
- Impact: Although drift detection is now CE, using GitHub Issues notifications imposes an EE dependency (the example workflow requires `ee: 'true'`). Slack notifications remain CE-only and do not require EE.
123+
- Proposed fix (upcoming commit): Promote the GitHub Issues drift notification provider to CE by adding a CE implementation (e.g., `cli/pkg/drift/github_issue.go`) and extending the CE provider to honor `INPUT_DRIFT_GITHUB_ISSUES`. Update docs to remove the `ee: 'true'` requirement for Issues after the change.
124+
- Interim docs: Until the provider is promoted to CE, users need `ee: 'true'` in the workflow to enable GitHub Issues notifications for drift.
125+
126+
## Final Notes
127+
128+
- CE Issues notifier: Promoted to CE and wired into the CE provider (`INPUT_DRIFT_GITHUB_ISSUES`). Docs updated to remove `ee: 'true'` for Issues workflows.
129+
- Terraform setup in examples: In drift-detection workflows, include `setup-terraform: true` so Terraform is installed in the runner.
130+
- EE CLI dedupe: EE now instantiates CE notifiers (basic Slack + GitHub Issues); removed the duplicate EE Issues notifier file.
131+
- CI parity tip: To reproduce EE backend test failures locally, run with the workspace off: `cd ee/backend && GOWORK=off go test ./...`.
132+
- Middleware constants: Using `backend/middleware` is safe; it defines `ORGANISATION_ID_KEY` and related keys with identical values to the drift middleware.
133+
- Workspace modules: Keep both `./drift` and `./ee/drift` in `go.work` (EE wrapper remains buildable alongside CE).
134+
- Secrets split: Drift service uses `DIGGER_WEBHOOK_SECRET`, backend uses `DIGGER_INTERNAL_SECRET`. Current behavior unchanged; unification can be a follow-up.
135+
- Dockerfile hygiene: Addressed build warnings (FROM … AS casing; `ENV key=value`).
136+
137+
Optional next cleanups (follow-ups)
138+
- Confirm whether `ee/drift/scripts/cron/notifications.sql` is still required; move it to `drift/scripts/cron/` or remove if obsolete.
139+
- Update reference docs to explicitly list `INPUT_DRIFT_GITHUB_ISSUES` under CE drift-detection inputs.

cli/pkg/drift/github_issue.go

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package drift
2+
3+
import (
4+
"fmt"
5+
orchestrator "github.com/diggerhq/digger/libs/ci"
6+
"github.com/samber/lo"
7+
"log"
8+
)
9+
10+
type GithubIssueNotification struct {
11+
GithubService *orchestrator.PullRequestService
12+
RelatedPrNumber *int64
13+
}
14+
15+
func (ghi *GithubIssueNotification) SendNotificationForProject(projectName string, repoFullName string, plan string) error {
16+
log.Printf("Info: Sending drift notification regarding project: %v", projectName)
17+
title := fmt.Sprintf("Drift detected in project: %v", projectName)
18+
message := fmt.Sprintf(":bangbang: Drift detected in digger project %v details below: \n\n```\n%v\n```", projectName, plan)
19+
existingIssues, err := (*ghi.GithubService).ListIssues()
20+
if err != nil {
21+
log.Printf("failed to retrieve issues: %v", err)
22+
return fmt.Errorf("failed to retrieve issues: %v", err)
23+
}
24+
25+
theIssue, exists := lo.Find(existingIssues, func(item *orchestrator.Issue) bool {
26+
return item.Title == title
27+
})
28+
if exists {
29+
_, err := (*ghi.GithubService).UpdateIssue(theIssue.ID, theIssue.Title, message)
30+
if err != nil {
31+
log.Printf("error while updating issue: %v", err)
32+
}
33+
return err
34+
} else {
35+
labels := []string{"digger"}
36+
_, err := (*ghi.GithubService).PublishIssue(title, message, &labels)
37+
if err != nil {
38+
log.Printf("error while publishing issue: %v", err)
39+
}
40+
return err
41+
}
42+
}
43+
44+
func (ghi *GithubIssueNotification) SendErrorNotificationForProject(projectName string, repoFullName string, err error) error {
45+
return nil
46+
}
47+
48+
func (ghi *GithubIssueNotification) Flush() error {
49+
return nil
50+
}
51+

cli/pkg/drift/Provider.go renamed to cli/pkg/drift/provider.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,14 @@ type DriftNotificationProviderBasic struct{}
1515

1616
func (d DriftNotificationProviderBasic) Get(prService ci.PullRequestService) (core_drift.Notification, error) {
1717
slackNotificationUrl := os.Getenv("INPUT_DRIFT_DETECTION_SLACK_NOTIFICATION_URL")
18+
githubIssues := os.Getenv("INPUT_DRIFT_GITHUB_ISSUES")
1819
var notification core_drift.Notification
1920
if slackNotificationUrl != "" {
2021
notification = &SlackNotification{slackNotificationUrl}
22+
} else if githubIssues != "" {
23+
notification = &GithubIssueNotification{GithubService: &prService}
2124
} else {
22-
return nil, fmt.Errorf("could not identify drift mode, please specify slack using env variable INPUT_DRIFT_DETECTION_SLACK_NOTIFICATION_URL")
25+
return nil, fmt.Errorf("could not identify drift mode, please specify using INPUT_DRIFT_DETECTION_SLACK_NOTIFICATION_URL or INPUT_DRIFT_GITHUB_ISSUES")
2326
}
2427
return notification, nil
2528
}

docs/ce/features/drift-detection.mdx

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@ title: "Drift Detection"
33
---
44

55

6+
<Note>
7+
Drift detection has been promoted from EE to CE and is now available to all Community Edition users. The examples below show how to configure scheduled drift checks and notifications.
8+
</Note>
9+
610
# Drift alerts via Slack
711

812
## Create a separate workflow file for drift
@@ -47,10 +51,41 @@ Note the `DRIFT_DETECTION_SLACK_NOTIFICATION` env var that the workflow above is
4751
Follow the [official Slack guide](https://api.slack.com/messaging/webhooks) to get the Incoming Webhook URL; then add it as an Action secret named `DRIFT_DETECTION_SLACK_NOTIFICATION`
4852

4953

50-
# Drift alerts via Github Issues
54+
# Drift alerts via GitHub Issues
55+
56+
Digger supports drift detection and automatic creation of issues in your ticketing system, e.g. GitHub Issues. Configure a scheduled workflow that enables GitHub Issues notifications:
57+
58+
```
59+
name: Drift Detection
60+
61+
on:
62+
workflow_dispatch:
63+
#schedule: ## Schedule the job to run at 12.am daily.
64+
# - cron: '0 0 * * *'
5165
52-
Coming soon to CE, here is an example of how to configure it: https://github.com/diggerhq/demo-ee-features/edit/main/.github/workflows/drift.yml.
53-
Digger supports drift detection and automatic creation of issues in your ticketing system, e.g. GitHub Issues:
66+
jobs:
67+
detect-drift:
68+
runs-on: ubuntu-latest
69+
steps:
70+
- name: digger drift detection
71+
uses: diggerhq/digger@vLatest
72+
with:
73+
mode: drift-detection
74+
setup-aws: true
75+
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
76+
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
77+
no-backend: true
78+
env:
79+
GITHUB_CONTEXT: ${{ toJson(github) }}
80+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
81+
DIGGER_GITHUB_TOKEN: ${{ secrets.DIGGER_GITHUB_TOKEN }}
82+
INPUT_DRIFT_GITHUB_ISSUES: 'true'
83+
# DIGGER_MANAGEMENT_REPO: "https://github.com/your-org/your-mgmt-repo"
84+
```
85+
86+
<Note>
87+
The example above creates GitHub Issues when drift is detected. Ensure `${{ secrets.GITHUB_TOKEN }}` (or a PAT) has permission to create issues in the repository.
88+
</Note>
5489

5590
<img height="400" src="/images/drift-issues.png" />
5691

@@ -59,4 +94,4 @@ Digger supports drift detection and automatic creation of issues in your ticketi
5994
## 403 errors
6095

6196
If you are seeing permission errors such as 403 in the action log while reporting drift status the backend that is almost always due to missing `no-backend: true`
62-
as an argument in the workflow file
97+
as an argument in the workflow file

drift/.dockerignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# flyctl launch added from .gitignore
2+
**/.env
3+
fly.toml

drift/.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.env
2+
main
3+
drift

ee/drift/controllers/ci_jobs.go renamed to drift/controllers/ci_jobs.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ package controllers
22

33
import (
44
"github.com/diggerhq/digger/backend/models"
5-
"github.com/diggerhq/digger/ee/drift/middleware"
5+
"github.com/diggerhq/digger/drift/middleware"
66
orchestrator_scheduler "github.com/diggerhq/digger/libs/scheduler"
77
"log"
88
"log/slog"
File renamed without changes.

ee/drift/controllers/drift.go renamed to drift/controllers/drift.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ import (
1212
"time"
1313

1414
"github.com/diggerhq/digger/backend/ci_backends"
15-
services2 "github.com/diggerhq/digger/ee/drift/services"
16-
"github.com/diggerhq/digger/ee/drift/utils"
15+
services2 "github.com/diggerhq/digger/drift/services"
16+
"github.com/diggerhq/digger/drift/utils"
1717
"github.com/diggerhq/digger/libs/ci/generic"
1818
dg_configuration "github.com/diggerhq/digger/libs/digger_config"
1919
"github.com/diggerhq/digger/libs/scheduler"

0 commit comments

Comments
 (0)