Merge/sharepoint into hermes#699
Conversation
- 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.
|
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/...)
There was a problem hiding this comment.
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-pluginOffice 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.
| // 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) |
| // 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) |
| @@ -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 |
| # Update the package repository and install dependencies | ||
| RUN apk --no-cache update && \ | ||
| apk --no-cache upgrade |
| { | ||
| 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"` | |||
| // 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. |
| graphURL := fmt.Sprintf("https://graph.microsoft.com/v1.0/users/%s/memberOf?$select=id,displayName,mail", | ||
| url.QueryEscape(userEmail)) |
| 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 | ||
| } |
| } | ||
|
|
||
| // 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()) |
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
configs/config.hcl, allowing deployments to use SharePoint and Microsoft Graph instead of Google Workspace.hermes-plugindirectory 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
.github/workflows/docker-build-push.ymlfor automated Docker image build and push, and updated.github/workflows/ci.ymlto support workflow dispatch, Go 1.24, plugin build, and improved build/test steps. [1] [2] [3]Makefileto add plugin build targets and newbuild/linuxtarget for improved build process. [1] [2]Dependency Upgrades
go.modfor improved compatibility and security, includinggolang-jwt,golang.org/x/oauth2, and various indirect dependencies. [1] [2] [3] [4] [5]Docker Support
Dockerfilefor containerizing the application, supporting deployment in Docker environments.Ownership and Team Assignment
.github/CODEOWNERSto include@hashicorp/team-scale-performance-engfor repository ownership.