Skip to content

Merge/sharepoint into hermes#699

Closed
sjaiswalh wants to merge 27 commits into
mainfrom
merge/sharepoint-into-hermes
Closed

Merge/sharepoint into hermes#699
sjaiswalh wants to merge 27 commits into
mainfrom
merge/sharepoint-into-hermes

Conversation

@sjaiswalh
Copy link
Copy Markdown
Collaborator

This pull request introduces major improvements for supporting SharePoint and Microsoft Office Add-in integration, updates build and CI workflows, and upgrades dependencies for compatibility and security. The most important changes are grouped below.

SharePoint and Office Add-in Integration

  • Added SharePoint and Microsoft authentication configuration options to configs/config.hcl, allowing deployments to use SharePoint and Microsoft Graph instead of Google Workspace.
  • Introduced the new hermes-plugin directory with Office Add-in assets, manifest, build configuration, and handler (addin.go) for serving the add-in as a single-page application. [1] [2] [3] [4] [5] [6]

Build and CI Workflow Updates

  • Created .github/workflows/docker-build-push.yml for automated Docker image build and push, and updated .github/workflows/ci.yml to support workflow dispatch, Go 1.24, plugin build, and improved build/test steps. [1] [2] [3]
  • Updated Makefile to add plugin build targets and new build/linux target for improved build process. [1] [2]

Dependency Upgrades

  • Upgraded Go version to 1.24 and updated multiple dependencies in go.mod for improved compatibility and security, including golang-jwt, golang.org/x/oauth2, and various indirect dependencies. [1] [2] [3] [4] [5]

Docker Support

  • Added a new Dockerfile for containerizing the application, supporting deployment in Docker environments.

Ownership and Team Assignment

  • Updated .github/CODEOWNERS to include @hashicorp/team-scale-performance-eng for repository ownership.

- Revert dashboard new-features-banner to original dismissible feature banner
- Revert isShown logic to localStorage-based (was hardcoded to 'return true')
- Remove permanent-migration-banner CSS and pulseRed animation from dashboard.scss
- Delete document/sidebar/migration-banner component (hbs + ts)
- Remove MigrationBanner reference from document/sidebar.hbs
- Add MERGE_PLAN.md for sharepoint merge tracking
- Upgrade go.mod to Go 1.24.0 with SharePoint dependencies
- Add back Google-specific deps (cloud.google.com/go, genproto)
- Copy 20 new packages: microsoftgraph, sharepointhelper, auth/microsoft,
  auth/oidcalb, auth/sharepoint, middleware, etc.
- Copy 55 differing files from hermes-sharepoint
- Merge Document model (Option A): dual GoogleFileID + FileID fields
  - Add GetFileIdentifier() and hasNoFileID() helpers
  - Add BeforeCreate validation hook
  - Fix all 7 redundant vet errors (d.FileID == '' && d.FileID == '')
  - Update query patterns for dual-field lookups
- Merge auth.go: 4-tier auth (OIDC ALB > Okta > Microsoft > Google)
- Add Okta backward compat in config.go
- Copy hermes-plugin for Go embed compilation
- All builds pass (go build ./..., go vet ./...)
- pkg/models tests pass
- Replace web/ entirely with hermes-sharepoint frontend (Ember 3.28 -> 5.8)
- Clean hermes-plugin manifests: keep only manifest.xml
- Remove enterprise AppDomain (hashicorp.com) from manifest.xml
- Update Makefile: add plugin/build and build/linux targets
- Build verified: go build ./... passes
- Add Dockerfile (public alpine:3.21.5, no enterprise mirror)
- Update ci.yml: Go 1.24, add plugin build, workflow_dispatch
- Add docker-build-push.yml (generic GHCR, no enterprise doormat)
- Merge CODEOWNERS: both @hashicorp-forge/labs and @hashicorp/team-scale-performance-eng
- Add SharePoint config templates to configs/config.hcl
- Remove hashicorp.services from CORS allowlist (cors.go)
- Fix draft doc number comparison bug: remove .docx from regex replacement
- Fix v1 test to use SP draft format (ABC-xxx.docx)
- Fix v2 test to use original format (ABC-???) matching v2 regex
- All tests pass: go build ./... && go test ./...
…gin/

macOS cp -R did not copy hidden files when target directory existed.
This restores all missing dotfiles (.eslintrc.js, .gitignore, .yarnrc.yml,
tsconfig.json, postcss.config.js, testem.js, etc.) and hermes-plugin source
files (package.json, src/, assets/, webpack.config.js, manifest.xml, etc.).

Removes nested src/src/ and assets/assets/ created by cp -R on existing dirs.
Removes enterprise AppDomain from hermes-plugin/manifest.xml.

Verified: make build passes (web + plugin + go), go test ./... all pass.
@sjaiswalh sjaiswalh requested a review from a team as a code owner March 10, 2026 05:00
@hashicorp-cla-app
Copy link
Copy Markdown

CLA assistant check

Thank you for your submission! We require that all contributors sign our Contributor License Agreement ("CLA") before we can accept the contribution. Read and sign the agreement

Learn more about why HashiCorp requires a CLA and what the CLA includes

Have you signed the CLA already but the status is still pending? Recheck it.

…template

- Remove hermes-plugin/dist/ from git tracking (build artifact, gitignored)
- Remove unused microsoft_auth/microsoft_graph blocks from configs/config.hcl
- Update email from_address to Microsoft tenant user
Restored in documents.go:
- IsLocked check (Google-only guard) in PATCH handler
- Added hcd import

Restored in drafts.go:
- IsLocked check (Google-only guard) in PATCH handler
- Owner photo lookup via SearchPeople in POST handler
- Create-as-user flow with impersonation + MoveFile + TemporaryDraftsFolder
- Ownership transfer email with SearchPeople name lookups
- Added imports: context, hcd, jwt, drive/v3, option

Restored in reviews.go:
- IsLocked check (Google-only guard) before database transaction
- MoveFile to DocsFolder with revert function on review creation
- Added hcd import
- Empty publishReaderGroups and publishGroupDisplayNames in documents.go
- Use GetFileIdentifier() instead of .FileID for DB-loaded documents
  in documents_related_resources.go and projects_related_resources.go
- Fix model Create() Where clauses to dynamically query google_file_id
  or file_id based on which field is populated
- Wrap SharePoint-only filename sanitization in srv.SharePoint != nil
  conditional in drafts.go
Production code fixes (16 files):
- Restore Google domain sharing in drafts_shareable.go (wrapped in useSharePoint guard)
- Restore createGoogleShortcut in v2/reviews.go alongside createSharePointShortcut
- Restore email notifications in v1/reviews.go with EmailSenderAdapter
- Restore entire Google indexing path (runGoogleWorkspace) in indexer.go
- Fix validate() to require at least one backend, not mandate SharePoint
- Restore auth conditional in server.go (OidcAlb/Okta web auth)
- Fix .FileID bugs to use GetFileIdentifier() in 5 API handler files (v1+v2)
- Fix FileID-only validation to use hasNoFileID() in document_review.go,
  document_group_review.go, document_related_resource_external_link.go
- Add dual-provider design comments in document.go, document_file_revision.go
- Fix new-owner email in drafts.go to be dual-backend aware

Test files (8 files):
- Revert test files to use GoogleFileID (restore original Google path coverage)
- Fix document_file_revision_test.go for FileRevisionID (new PK) and pointer type
- Add TestDocumentDualBackend: parameterized Create/Get/Upsert/Delete for both backends
- Add TestDocumentDualBackendCoexistence: Google + SharePoint docs coexist,
  independent CRUD, GetFileIdentifier(), hasNoFileID() validation
- Add TestDocumentReviewDualBackend: review Get/Update/Find for both backends
- Add TestDocumentGroupReviewDualBackend: group review Get/Find for both backends
- Add TestDocumentFileRevisionDualBackend: revision Create/Find for both backends

All changes compile clean (go build ./... and go vet ./pkg/models/...)
@sjaiswalh sjaiswalh requested a review from Copilot March 13, 2026 17:30
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR merges SharePoint/Microsoft Graph and Office Add-in support into Hermes, updates build/CI to include the plugin and Go 1.24, and refactors several APIs/models away from Google-specific identifiers.

Changes:

  • Added SharePoint/Microsoft Graph support paths across v2 APIs (people, groups, me, related resources) and introduced FileID/GetFileIdentifier() usage.
  • Introduced hermes-plugin Office Add-in SPA assets and a Go handler to serve the embedded build.
  • Updated build/CI workflows, Docker packaging, and upgraded Go/dependencies for compatibility/security.

Reviewed changes

Copilot reviewed 87 out of 485 changed files in this pull request and generated 12 comments.

Show a summary per file
File Description
internal/api/v2/projects_related_resources.go Renames document identifier fields and uses unified file identifier accessor.
internal/api/v2/projects.go Adds request validation logging for common query/body errors.
internal/api/v2/people.go Adds SharePoint (Graph) support for people search, photo fetching, and email lookup.
internal/api/v2/me_recently_viewed_docs.go Uses unified file identifier for recently viewed docs.
internal/api/v2/me.go Adds SharePoint (Graph) profile path and a unified MeGetResponse.
internal/api/v2/helpers_test.go Updates tests for renamed document identifiers and file revision fields.
internal/api/v2/helpers.go Makes email comparisons case-insensitive; adds group expansion and Graph-backed group membership checks.
internal/api/v2/groups.go Adds SharePoint group search path and refactors response writing + dedupe helpers.
internal/api/v2/drafts_shareable.go Adds SharePoint-aware model lookup and logs unauthorized shareable changes.
internal/api/v2/drafts_archived.go Adds new drafts archived GET/PATCH handler with DB + Algolia update.
internal/api/v2/documents_test.go Adds tests for case-insensitive authorization behaviors.
internal/api/v2/documents_related_resources.go Makes related resources handler SharePoint-aware and switches to unified identifiers.
internal/api/reviews.go Uses unified document construction; enriches email payload; introduces sender adapter usage.
internal/api/me_recently_viewed_docs.go Uses unified file identifier for v1 recently viewed docs.
internal/api/helpers_test.go Updates v1 helper tests for identifier/doc number changes.
internal/api/helpers.go Updates v1 helper logic for identifiers and draft doc number normalization.
internal/api/drafts_shareable.go Updates v1 drafts shareable DB lookup to new document constructor.
internal/api/drafts.go Attempts to add Microsoft Graph draft creation / MS template support; updates draft naming scheme.
internal/api/documents_related_resources.go Updates v1 related resources handler to new identifier fields.
internal/api/documents.go Updates v1 document handlers to use new document constructor fields.
internal/api/approvals.go Adds SharePoint-aware branching (currently forced off) and refactors review DB updates.
hermes-plugin/webpack.config.js Adds Office add-in webpack build and dev server configuration.
hermes-plugin/tsconfig.json Adds TypeScript configuration for the plugin build.
hermes-plugin/src/taskpane/utils/timeAgo.ts Adds timestamp-to-relative-time helper.
hermes-plugin/src/taskpane/utils/themeContext.tsx Adds theme context and persisted toggle.
hermes-plugin/src/taskpane/utils/storageAccess.ts Adds Storage Access API utilities to support third-party cookie constraints.
hermes-plugin/src/taskpane/utils/productUtils.ts Adds product hashing/color helpers and dasherize utility.
hermes-plugin/src/taskpane/utils/lightTheme.ts Adds light theme constants.
hermes-plugin/src/taskpane/utils/darkTheme.ts Adds dark theme constants and shared style utilities.
hermes-plugin/src/taskpane/utils/authPopup.ts Adds Office Dialog-based auth flow helpers + Storage Access integration.
hermes-plugin/src/taskpane/taskpane.ts Adds Word document interaction helpers (header parsing/updating).
hermes-plugin/src/taskpane/taskpane.html Adds taskpane HTML entry for Office add-in.
hermes-plugin/src/taskpane/interfaces/relatedResources.ts Adds plugin-side types/helpers for related resources and update formatting.
hermes-plugin/src/taskpane/interfaces/project.ts Adds project types/status colors for plugin UI.
hermes-plugin/src/taskpane/interfaces/products.ts Adds product interface for plugin usage.
hermes-plugin/src/taskpane/interfaces/person.ts Adds People API response typings for plugin.
hermes-plugin/src/taskpane/interfaces/group.ts Adds group typing for plugin.
hermes-plugin/src/taskpane/interfaces/documentMetadata.ts Adds document metadata type used by the plugin taskpane.
hermes-plugin/src/taskpane/interfaces/currentUser.ts Adds current user type for /me response usage.
hermes-plugin/src/taskpane/index.tsx Adds plugin bootstrap: HermesClient + Word controller + FluentProvider.
hermes-plugin/src/taskpane/components/ThemeToggleButton.tsx adds UI for toggling theme.
hermes-plugin/src/taskpane/components/RelatedResourcesList.tsx Adds related resources list UI + add/edit flows.
hermes-plugin/src/taskpane/components/RelatedResourceItem.tsx Adds item renderer and open/edit/remove behaviors.
hermes-plugin/src/taskpane/components/ProjectsList.tsx Adds project association UI with search and add/remove flows.
hermes-plugin/src/taskpane/components/ProjectStatusIcon.tsx Adds status icon rendering for projects.
hermes-plugin/src/taskpane/components/ProjectIcon.tsx Adds project icon SVG.
hermes-plugin/src/taskpane/components/ProductIcon.tsx Adds product badge rendering (icons/abbr/fallback).
hermes-plugin/src/taskpane/components/EditableText.tsx Adds editable text field component with inline save/cancel.
hermes-plugin/src/taskpane/components/EditResourceForm.tsx Adds inline edit form for external link resources.
hermes-plugin/src/taskpane/components/EditRelatedResourceModal.tsx Adds modal editor for external link resources.
hermes-plugin/src/taskpane/components/DocumentThumbnail.tsx Adds document thumbnail with product/status overlays.
hermes-plugin/src/taskpane/components/AddRelatedResourceModal.tsx Adds modal to create external related resources.
hermes-plugin/src/safari-init/safari-init.ts Adds Safari-specific auth bootstrap with redirect validation.
hermes-plugin/src/safari-init/safari-init.html Adds Safari init HTML with CSP.
hermes-plugin/src/safari-init/safari-init.css Adds Safari init styling.
hermes-plugin/src/config.json Adds plugin runtime config (baseUrl/useHostUrl).
hermes-plugin/src/commands/commands.ts Adds Office “commands” handler (template-based).
hermes-plugin/src/commands/commands.html Adds commands HTML entry.
hermes-plugin/src/auth-callback.ts Adds OAuth callback handling and secure UI rendering.
hermes-plugin/src/auth-callback.html Adds OAuth callback HTML entry.
hermes-plugin/set_keywords_helper.js Adds helper to set document keywords via Word JS API.
hermes-plugin/package.json Adds plugin Node dependencies, build scripts, and lint config.
hermes-plugin/manifest.xml Adds Word add-in manifest.
hermes-plugin/manifest.json Adds Teams manifest (template).
hermes-plugin/babel.config.json Adds Babel config for plugin build transpilation.
hermes-plugin/addin.go Adds Go handler embedding+serving plugin dist bundle.
hermes-plugin/.hintrc Adds webhint config (typescript strict off).
hermes-plugin/.gitignore Adds plugin gitignore entries.
hermes-plugin/.eslintrc.json Adds plugin ESLint config for office add-ins.
go.mod Upgrades Go version and dependency set (oauth2, jwt, x/*, grpc, etc.).
configs/config.hcl Adds commented SharePoint + OIDC ALB config examples.
Makefile Adds plugin build target and linux build variant.
Dockerfile Adds container packaging for the Hermes binary + configs.
.github/workflows/docker-build-push.yml Adds GHCR build/push workflow building web+plugin+Go binary.
.github/workflows/ci.yml Updates CI to Go 1.24, builds plugin, and rearranges steps.
.github/CODEOWNERS Adds additional code owner team.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread internal/api/drafts.go
Comment on lines +116 to +121
// Check if we're using Microsoft Graph (if it's available in the server)
useMicrosoftGraph := false
if srv, ok := interface{}(s).(*server.Server); ok {
useMicrosoftGraph = srv.SharePoint != nil
}
template := getDocTypeTemplate(cfg.DocumentTypes.DocumentType, req.DocType, useMicrosoftGraph)
Comment thread internal/api/drafts.go
Comment on lines 191 to +213
// Move draft file to drafts folder using service user.
_, err = s.MoveFile(
f.Id, cfg.GoogleWorkspace.DraftsFolder)
if err != nil {
l.Error(
"error moving draft file to drafts folder",
"error", err,
"method", r.Method,
"path", r.URL.Path,
"doc_id", f.Id,
"template", template,
"drafts_folder", cfg.GoogleWorkspace.DraftsFolder,
"temporary_drafts_folder", cfg.GoogleWorkspace.
TemporaryDraftsFolder,
)
http.Error(w, "Error creating document draft",
http.StatusInternalServerError)
return
}
}

// Move draft file to drafts folder using service user.
_, err = s.MoveFile(
f.Id, cfg.GoogleWorkspace.DraftsFolder)
Comment on lines +1 to +19
@@ -1,18 +0,0 @@
<!-- Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT License. -->

<!DOCTYPE html>
<html>

<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />

<!-- Office JavaScript API -->
<script type="text/javascript" src="https://appsforoffice.microsoft.com/lib/1/hosted/office.js"></script>
</head>

<body>

</body>

</html> No newline at end of file
Comment thread Dockerfile
Comment on lines +3 to +5
# Update the package repository and install dependencies
RUN apk --no-cache update && \
apk --no-cache upgrade
Comment on lines +46 to +57
{
test: /\.ts$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
},
},
{
test: /\.tsx?$/,
exclude: /node_modules/,
use: ["ts-loader"],
},
@@ -23,7 +23,7 @@ type ProjectRelatedResourcesGetResponseExternalLink struct {
}

type ProjectRelatedResourcesGetResponseHermesDocument struct {
GoogleFileID string `json:"googleFileID"`
FileID string `json:"FileID"`
Comment on lines +55 to +57
// expandStakeholderGroups expands any groups in the stakeholders list to their individual members recursively.
// It handles nested groups (group within group within group) by using the backend service's
// group member expansion methods.
Comment on lines +635 to +636
graphURL := fmt.Sprintf("https://graph.microsoft.com/v1.0/users/%s/memberOf?$select=id,displayName,mail",
url.QueryEscape(userEmail))
Comment on lines +644 to +671
resp, err := srv.SharePoint.InvokeAPIWithOptions("GET", graphURL, nil, options)
if err != nil {
return false, fmt.Errorf("error making Graph API request for user groups: %w", err)
}
defer resp.Body.Close()

if resp.StatusCode != http.StatusOK {
return false, fmt.Errorf("microsoft Graph API returned status %d when fetching user groups", resp.StatusCode)
}

// Parse the response
var response struct {
Value []struct {
ID string `json:"id"`
DisplayName string `json:"displayName"`
Mail string `json:"mail"`
} `json:"value"`
}

if err := json.NewDecoder(resp.Body).Decode(&response); err != nil {
return false, fmt.Errorf("error decoding user groups response: %w", err)
}

// Check if any of the user's groups match the provided group emails
for _, group := range response.Value {
if group.Mail != "" && contains(groupEmails, group.Mail) {
return true, nil
}
Comment thread internal/api/v2/me.go
}

// Set the profile picture URL to use our backend API v2
pictureURL := fmt.Sprintf("/api/v2/people?photo=%s&v=%d", url.QueryEscape(email), time.Now().Unix())
@sjaiswalh sjaiswalh closed this Mar 13, 2026
@sjaiswalh sjaiswalh deleted the merge/sharepoint-into-hermes branch March 13, 2026 17:49
@sjaiswalh sjaiswalh restored the merge/sharepoint-into-hermes branch March 27, 2026 05:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants