Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
92e787d
Remove migration/deprecation banners
sjaiswalh Mar 9, 2026
0ad81d9
Phase 2: Merge SharePoint backend into hermes
sjaiswalh Mar 9, 2026
eb77b08
Phase 3: Upgrade frontend to Ember 5 + Word Add-in cleanup
sjaiswalh Mar 9, 2026
4103ad1
Phase 4: Update CI/CD, Dockerfile, and configuration
sjaiswalh Mar 9, 2026
146537c
Phase 5: Cleanup enterprise values and fix tests
sjaiswalh Mar 9, 2026
1db7775
fix: restore missing dotfiles and config files in web/ and hermes-plu…
sjaiswalh Mar 9, 2026
6e98368
fix: remove accidentally tracked hermes-plugin/dist and clean config …
sjaiswalh Mar 10, 2026
0a2d8b7
feat: implement dual-backend SharePoint/Google support across all API…
sjaiswalh Mar 10, 2026
1d5cb83
Fix FileID/GoogleFileID dual-field lookups across all handlers
sjaiswalh Mar 10, 2026
299d849
Remove MERGE_PLAN.md from branch
sjaiswalh Mar 10, 2026
b3c788a
Fix formatting/indentation (gofmt)
sjaiswalh Mar 10, 2026
89f4ec1
Restore hcd.IsLocked checks in v2 approvals handler (lost in Phase 2 …
sjaiswalh Mar 10, 2026
a85eec3
Guard IsLocked checks with !srv.IsSharePoint() (Google-only concern)
sjaiswalh Mar 10, 2026
1621ed7
Restore ReplaceHeader calls lost in Phase 2 merge (guarded for Google…
sjaiswalh Mar 10, 2026
fa76076
Restore remaining Google-only functions lost in Phase 2 merge
sjaiswalh Mar 10, 2026
c20b6e1
fix: dual-backend support for Google and SharePoint
sjaiswalh Mar 10, 2026
2cbd708
Restore dual-backend support and add comprehensive tests
sjaiswalh Mar 11, 2026
2a220d0
fix: restore Google mode support across frontend and backend (18 files)
sjaiswalh Mar 11, 2026
b517742
fix: remove SharePoint default init that breaks Google mode, add nil …
sjaiswalh Mar 11, 2026
240c7e7
fix: resolve TS errors in document route (null check, await async)
sjaiswalh Mar 11, 2026
7518dac
Fix SharePoint auth flow and add-in reauth
sjaiswalh Mar 12, 2026
59e14d5
Retry published PATCH after draft 404
sjaiswalh Mar 12, 2026
10ed77d
Fix published ownership transfer checks
sjaiswalh Mar 12, 2026
fbe699d
Fix dual-backend document and auth flows
sjaiswalh Mar 13, 2026
e432a23
Refine auth probes and startup routing
sjaiswalh Mar 13, 2026
ad0e52d
We don't index published folder in sharepoint version
sjaiswalh Mar 13, 2026
3a7cd07
Update add-in manifest
sjaiswalh Mar 13, 2026
d5ed5c6
Handle paginated Graph memberOf lookups
sjaiswalh Mar 27, 2026
43154be
Make draft archive owner check case-insensitive
sjaiswalh Mar 27, 2026
e2f51e3
Update readme and sample config
sjaiswalh Mar 27, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 1 addition & 1 deletion .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -1 +1 @@
* @hashicorp-forge/labs
* @hashicorp-forge/labs @hashicorp/team-scale-performance-eng
19 changes: 9 additions & 10 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ on:
branches: [main]
push:
branches: [main]
workflow_dispatch:

jobs:
build-and-test:
Expand All @@ -24,28 +25,26 @@ jobs:
run: |
corepack enable
cd web
# Remove .yarnrc.yml to let corepack handle yarn version
rm -f .yarnrc.yml
corepack prepare yarn@$(node -p "require('./package.json').packageManager.split('@')[1]") --activate
yarn --version

- name: Set up Go
uses: actions/setup-go@v4
with:
go-version: "^1.18"

- name: Verify Yarn version
run: cd web && yarn --version
go-version: "^1.24"

- name: Build web
run: cd web && yarn install && yarn build

- name: Run web test (continue on failure)
run: cd web && yarn test:ember --timeout 600000 || true
continue-on-error: true
- name: Build plugin
run: cd hermes-plugin && npm install && npm run build

- name: Build
- name: Build Go binary
run: make bin/linux

- name: Run Go test
run: make go/test

- name: Run web test (continue on failure)
run: cd web && yarn test:ember --timeout 600000 || true
continue-on-error: true
48 changes: 48 additions & 0 deletions .github/workflows/docker-build-push.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
name: Docker Build & Push

on:
push:
branches: [main]
workflow_dispatch:

jobs:
build-and-push:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v3

- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: "18"

- name: Enable Corepack
run: |
corepack enable
cd web
corepack prepare yarn@$(node -p "require('./package.json').packageManager.split('@')[1]") --activate

- name: Set up Go
uses: actions/setup-go@v4
with:
go-version: "^1.24"

- name: Build
run: make build/linux

- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ghcr.io/${{ github.repository }}:${{ github.sha }}
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
.DS_Store
.env

# TLS certs (local dev)
/certs

# Web application
node_modules
/web/.pnp.*
Expand Down
18 changes: 18 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
FROM alpine:3.21.5

# Update the package repository and install dependencies
RUN apk --no-cache update && \
apk --no-cache upgrade

Comment thread
sjaiswalh marked this conversation as resolved.
# Set the working directory
WORKDIR /app

# Copy the application binary and configuration
COPY hermes /app/hermes
COPY configs /app/configs

# Set the entrypoint to run the hermes application
ENTRYPOINT ["/app/hermes"]

# Default command when container starts
CMD ["server"]
11 changes: 10 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
default: help

.PHONY: build
build: web/build
build: web/build plugin/build
rm -f ./hermes
CGO_ENABLED=0 go build -o ./hermes ./cmd/hermes

Expand All @@ -14,6 +14,15 @@ bin:
bin/linux: # bin creates hermes binary for linux
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o ./hermes ./cmd/hermes

.PHONY: build/linux
build/linux: web/build plugin/build
rm -f ./hermes
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o ./hermes ./cmd/hermes

.PHONY: plugin/build
plugin/build:
cd hermes-plugin && npm install && rm -rf dist/ && npm run build

.PHONY: dev
dev: ## One command to start a dev environment
dev: docker/postgres/start
Expand Down
84 changes: 84 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ Hermes was created and is currently maintained by HashiCorp Labs, a small team i

## Setup

Hermes supports two backend modes:

- Google Workspace
- SharePoint / Microsoft 365

### Google

1. Sign up for a [Google Workspace](https://workspace.google.com/) account.
Expand Down Expand Up @@ -92,6 +97,41 @@ Jira can be optionally configured to enable linking Hermes projects with Jira is

1. Enable Jira using the `jira` block in the Hermes config file.

### SharePoint / Microsoft 365

1. Create a Microsoft Entra ID app registration for Hermes.

1. Configure a redirect URI for the Hermes server.

- Local development example: `https://localhost:8443/authenticate`
- The redirect URI in Entra ID must match `sharepoint.redirect_uri` in `config.hcl`.

1. Create a client secret for the app registration.

1. Collect the values Hermes needs for configuration:

- Tenant ID
- Client ID
- Client secret
- SharePoint site ID
- SharePoint drive ID
- Your Microsoft 365 email domain (for example, `example.com`)

1. Create or identify the folders Hermes will use in the SharePoint document library:

- Drafts folder
- Published documents folder
- Shortcuts folder

1. Enable the `sharepoint` block in `config.hcl` and set the values above.

1. If you want Microsoft distribution lists to be selectable as approvers, enable the `group_approvals` block under `sharepoint`.

1. Choose an authentication mode:

- Direct Microsoft login: configure only the `sharepoint` block.
- ALB-fronted OIDC login: configure `sharepoint` and `oidc_alb`. Hermes prefers `oidc_alb` when it is enabled.

## Development and Usage

### Requirements
Expand All @@ -109,6 +149,36 @@ cp configs/config.hcl ./
# Edit config.hcl...
```

For Google Workspace deployments, configure the `google_workspace` block.

For SharePoint deployments, enable and configure the `sharepoint` block in `config.hcl`:

```hcl
sharepoint {
redirect_uri = "https://localhost:8443/authenticate"
client_id = "YOUR_SHAREPOINT_CLIENT_ID"
client_secret = "YOUR_SHAREPOINT_CLIENT_SECRET"
tenant_id = "YOUR_AZURE_AD_TENANT_ID"
site_id = "YOUR_SHAREPOINT_SITE_ID"
drive_id = "YOUR_SHAREPOINT_DRIVE_ID"
domain = "your-domain.com"
drafts_folder = "DraftDocuments"
docs_folder = "PublishedDocuments"
shortcuts_folder = "ShortcutsFolder"

group_approvals {
enabled = true
#search_prefix = "team-"
}
}
```

Notes:

- `group_approvals` is optional. When enabled, Hermes exposes the group search API and can validate Microsoft group membership for approver checks.
- `search_prefix` is optional. When set, Hermes searches both `{search_prefix}{query}` and `{query}` and merges the results.
- If `oidc_alb` is enabled, Hermes uses it ahead of direct Microsoft auth.

### Build the Project

```sh
Expand Down Expand Up @@ -140,8 +210,12 @@ The database password can be configured via the Hermes config.hcl or the `HERMES

NOTE: when not using a Google service account, this will automatically open a browser to authenticate the server to read and create documents, send emails, etc.

For SharePoint deployments without `oidc_alb`, Hermes uses the Microsoft login flow and serves the `/authenticate` callback route directly.

## Running Hermes in Production

### Google Workspace

1. [Create Service Account](https://developers.google.com/workspace/guides/create-credentials#service-account)

- Create a new key (JSON type) for the service account and download it.
Expand All @@ -153,6 +227,16 @@ NOTE: when not using a Google service account, this will automatically open a br

1. If enabling group approvals, add the `https://www.googleapis.com/auth/admin.directory.group.readonly` role to the service user configured as the `subject` in the `auth` block (from previous step).

### SharePoint / Microsoft 365

For SharePoint deployments, configure the `sharepoint` block instead of the Google service account.

- `redirect_uri` must match the app registration callback URL.
- `site_id` and `drive_id` identify the SharePoint document library Hermes will use.
- `drafts_folder`, `docs_folder`, and `shortcuts_folder` are the SharePoint folders Hermes manages.
- `group_approvals` is optional and enables Microsoft distribution-list search for approvers.
- `oidc_alb` is optional and can be used when Hermes is deployed behind an AWS ALB handling OIDC.

## Architecture

### Server
Expand Down
49 changes: 44 additions & 5 deletions configs/config.hcl
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// base_url is the base URL used for building links. This should be the public
// URL of the application.
base_url = "http://localhost:8000"

//base_url = "https://localhost:8443"
// log_format configures the logging format. Supported values are "standard" or
// "json".
log_format = "standard"
Expand Down Expand Up @@ -98,12 +98,12 @@ email {
feature_flags {
// api_v2 enables v2 of the API.
flag "api_v2" {
enabled = false
enabled = true
}

// projects enables the projects feature in the UI.
flag "projects" {
enabled = false
enabled = true
}
}

Expand Down Expand Up @@ -178,7 +178,7 @@ indexer {

// use_database_for_document_data will use the database instead of Algolia as
// the source of truth for document data, if true.
use_database_for_document_data = false
use_database_for_document_data = true
}

// jira is the configuration for Hermes to work with Jira.
Expand Down Expand Up @@ -238,8 +238,47 @@ products {
}
}

// --------------------------------------------------------------------------
// SharePoint Backend Configuration (alternative to google_workspace)
// --------------------------------------------------------------------------
// Uncomment and configure these blocks to use SharePoint instead of Google.

// sharepoint {
// redirect_uri = "https://localhost:8443/authenticate"
// client_id = "YOUR_SHAREPOINT_CLIENT_ID"
// client_secret = "YOUR_SHAREPOINT_CLIENT_SECRET"
// tenant_id = "YOUR_AZURE_AD_TENANT_ID"
// site_id = "YOUR_SHAREPOINT_SITE_ID"
// drive_id = "YOUR_SHAREPOINT_DRIVE_ID"
// domain = "your-domain.com"
//
// shortcuts_folder = "ShortcutsFolder"
// docs_folder = ""
//
// drafts_folder = ""
// group_approvals {
// enabled = true
// #search_prefix = "test-"
// }
// }

oidc_alb {
// auth_server_url is the OIDC discovery URL.
auth_server_url = "https://your-oidc-provider.com"
// aws_region is the region of the AWS ALB.
aws_region = "us-east-1"
// client_id is the OIDC client ID.
client_id = "ClientID"
// disabled disables OIDC ALB authorization.
disabled = false
// jwt_signer is the ARN of the ALB for JWT verification.
jwt_signer = "arn:aws:elasticloadbalancing:..."
}

// server contains the configuration for the server.
server {
// addr is the address to bind to for listening.
addr = "127.0.0.1:8000"
// addr = "0.0.0.0:8443"
// tls_cert = "/path/to/cert.pem"
// tls_key = "/path/to/key.pem"
}
Loading
Loading