Skip to content

Installation Validation: SharePoint Access#

System Criticality: Business-Critical Validation Approach: Risk-based Related Design: DESIGN:SharePointAccess Related URS: @URS:SharePointAccess Related Risks: RISK:SharePointAccess

Overview#

This Installation Validation (IV) plan validates the SharePoint Access MCP server against the documented requirements in @URS:SharePointAccess and mitigates risks identified in RISK:SharePointAccess. The SharePoint MCP server provides read-only access to SharePoint documents and OneDrive files via Microsoft Graph API, using OAuth2 On-Behalf-Of (OBO) authentication and multi-layer security controls.

Validation Scope: - User-scoped document access (OBO authentication enforces user permissions, not service-account access) - Sensitivity label enforcement (documents above configured max label are redacted, not returned in plaintext) - Read-only operations (write/upload/delete operations are not exposed and rejected by Graph API due to missing scopes) - No data persistence (document content never stored in DynamoDB or any persistent backend; only OAuth tokens cached) - Authentication enforcement (unauthenticated requests rejected before SharePoint data returned) - Site whitelist enforcement (if configured, access to non-whitelisted sites blocked at application layer)


Test Strategy#

Level Purpose Owner When Coverage
Unit Individual tool functions, filter logic Developers During dev Python unit tests with mocked Graph client
Integration Tool → Graph client → Microsoft Graph API QA After unit tests Dev environment with real Graph API, test accounts
System End-to-end user flows (search, browse, read) QA Before prod deployment Staging environment with production-like config
Security Authentication, authorization, sensitivity gates Security team Before prod deployment Penetration testing, vulnerability scans
Configuration Sensitivity labels, site whitelists, fail-closed behavior QA + Security After infra deploy Manual config testing in dev/staging

Test Environments: - Dev: sharepoint.dev.connectors.novo-genai.comECS task, memory-based token storage, LOG_LEVEL=DEBUG - Staging: Dev endpoint with production-like configuration (sensitivity labels, site whitelist loaded) - Prod: sharepoint.connectors.novo-genai.comECS task, DynamoDB token storage, LOG_LEVEL=INFO

Risk-Based Prioritization: - CRITICAL risks (R3: Sensitivity label bypass): 100% test coverage required, blocking gate for deployment - HIGH risks (R1: Token compromise, R2: Logging, R4: Whitelist bypass): 100% test coverage required, blocking gate - MEDIUM risks (R5: Parsing errors, R6: Graph API availability, R7: Query logging): Core scenarios tested, edge cases accepted


Traceability Matrix#

URS Scenario Summary Risk Test Case Type Priority Status
Authentication User authenticates via Azure AD OAuth2 R1 TEST-AUTH-001, TEST-AUTH-002 Integration CRITICAL Not Started
Search Documents Search across SharePoint sites R1, R3, R4, R7 TEST-SEARCH-001, TEST-SEARCH-002 System HIGH Not Started
Search with File Type Filter Filter by DOCX/PDF TEST-SEARCH-003 System MEDIUM Not Started
Search with Date Filter Filter by modification date TEST-SEARCH-004 System MEDIUM Not Started
Search with Author Filter Filter by author email TEST-SEARCH-005 System MEDIUM Not Started
List Sites Browse accessible SharePoint sites R1, R4 TEST-BROWSE-001 Integration HIGH Not Started
List Folder Navigate folder hierarchy R1, R4 TEST-BROWSE-002 Integration HIGH Not Started
Read Document Content Download and parse document R1, R2, R3, R5 TEST-READ-001, TEST-READ-002 System CRITICAL Not Started
Retrieve Metadata Fetch document metadata R1, R2 TEST-META-001 Integration MEDIUM Not Started
Sensitivity Label Enforcement Redact restricted documents R3 TEST-SEC-SENS-001 to 005 Security CRITICAL Not Started
Permission Enforcement User-scoped access control R1 TEST-SEC-PERM-001, TEST-SEC-PERM-002 Security CRITICAL Not Started
Read-Only Access No write/modify/delete operations TEST-SEC-READONLY-001 Security HIGH Not Started
No Data Persistence No SharePoint data cached/stored R2 TEST-SEC-PERSIST-001 Security HIGH Not Started
Whitelist Enforcement Block non-whitelisted sites R4 TEST-SEC-WHITELIST-001 to 003 Security CRITICAL Not Started
Logging Privacy No document content/filenames in logs R2, R7 TEST-SEC-LOGS-001, TEST-SEC-LOGS-002 Security HIGH Not Started

Coverage: 19 test cases covering 7 URS scenarios and 7 risk areas (Target: 100% for CRITICAL/HIGH risks)


Test Cases#

TEST-AUTH-001: OAuth2 OBO Authentication Flow#

Related: URS-Authentication | RISK-R1 Risk Level: CRITICAL Type: Integration

Preconditions: - SharePoint MCP server running in dev environment - Test user account exists: testuser-sharepoint-mcp@novonordisk.com - User has access to at least one SharePoint site - Azure AD app registration configured with correct scopes (Sites.Read.All, Files.Read.All, offline_access)

Steps: 1. Send MCP request to search_documents tool with invalid/missing Authorization header 2. Verify HTTP 401 Unauthorized response 3. Obtain OAuth2 Bearer token for test user via Azure AD authorization code flow 4. Send MCP request to search_documents tool with valid Bearer token in Authorization header 5. Verify MCP server exchanges token via OBO flow (check CloudWatch logs for obo_exchange_success event) 6. Verify search results returned (non-empty list) 7. Check CloudWatch logs for user identity in structured log fields (user_id, tenant_id)

Expected: - Step 1: HTTP 401 Unauthorized, error message: "Missing or invalid authorization token" - Step 2: HTTP 200 OK, valid MCP response with search results - Step 3: CloudWatch logs contain obo_exchange_success event with user_id matching test user - Step 4: All subsequent Graph API requests use user-scoped token (not service account token)

Pass Criteria: All expected results met; user identity preserved through token chain; no service account credentials used

Verification: RISK-R1OBO flow correctly implemented, user-scoped access enforced


TEST-AUTH-002: Expired Token Rejection#

Related: URS-Authentication | RISK-R1 Risk Level: CRITICAL Type: Integration

Preconditions: - SharePoint MCP server running in dev environment - Expired OAuth2 Bearer token available (manually generate with past expiry timestamp, or wait for token to expire naturally)

Steps: 1. Send MCP request to search_documents tool with expired Bearer token 2. Verify HTTP 401 Unauthorized response 3. Check CloudWatch logs for obo_exchange_failed event with error code invalid_token or token_expired

Expected: - HTTP 401 Unauthorized response - Error message: "Token expired or invalid" - No search results returned - No Graph API requests attempted after token validation failure

Pass Criteria: Expired tokens rejected before any Graph API calls; no data leakage

Verification: RISK-R1 — Token expiration enforced, limits window of unauthorized access


TEST-SEARCH-001: Cross-Site Document Search (Whitelisted Sites Only)#

Related: URS-Search Documents | RISK-R1, RISK-R4 Risk Level: HIGH Type: System

Preconditions: - SharePoint MCP server running with site whitelist configured: - Allowed: https://novonordisk.sharepoint.com/sites/TestSite1 - Allowed: https://novonordisk.sharepoint.com/sites/TestSite2 - NOT allowed: https://novonordisk.sharepoint.com/sites/RestrictedSite - Test documents exist in TestSite1, TestSite2, and RestrictedSite - Test user has SharePoint read permissions to all three sites (verifies whitelist enforced at app layer, not just Graph API)

Steps: 1. Authenticate as test user 2. Send search_documents request with query: "test document" 3. Verify search results returned 4. Check that all results have webUrl starting with allowed site prefixes 5. Verify no results from RestrictedSite appear (even though user has Graph API permissions)

Expected: - HTTP 200 OK response - Results include documents from TestSite1 and TestSite2 - Zero results from RestrictedSite - CloudWatch logs contain whitelist_filter_applied event with dropped_count > 0 (if RestrictedSite had matching documents)

Pass Criteria: Site whitelist correctly filters results; Graph API permissions alone insufficient to access non-whitelisted sites

Verification: RISK-R4 — Site whitelist enforcement at application layer (defense in depth)


TEST-SEARCH-002: Sensitivity Label Redaction in Search Results#

Related: URS-Sensitivity Labels | RISK-R3 Risk Level: CRITICAL Type: Security

Preconditions: - SharePoint MCP server running with sensitivity label config: - max_label: General - block_unlabeled: false - Test documents exist: - Public-Document.docx — labeled "Public" - General-Document.docx — labeled "General" - Confidential-Document.docx — labeled "Confidential" (above threshold) - Unlabeled-Document.docx — no sensitivity label

Steps: 1. Authenticate as test user 2. Send search_documents request with query matching all four documents 3. Verify all four documents appear in search results 4. For Confidential-Document.docx, verify: - _redacted: true field present - Metadata (name, webUrl, lastModifiedDateTime) still returned - sensitivityLabel.displayName = "Confidential" 5. For other documents, verify _redacted: false or field absent

Expected: - HTTP 200 OK response - Four documents in results - Confidential-Document.docx marked as _redacted: true - Public-Document.docx, General-Document.docx, Unlabeled-Document.docx marked as _redacted: false - CloudWatch logs contain sensitivity_gate_applied event with redacted_count: 1

Pass Criteria: Sensitivity gate correctly identifies documents above threshold; redacted items remain visible in results (transparency); metadata preserved

Verification: RISK-R3 — Sensitivity label gate enforced, prevents disclosure of restricted content


TEST-SEARCH-003: File Type Filter#

Related: URS-Search Documents | — Risk Level: MEDIUM Type: System

Preconditions: - Test documents exist: Report.docx, Budget.pdf, Data.xlsx, Presentation.pptx

Steps: 1. Authenticate as test user 2. Send search_documents request with file_types: ["docx", "pdf"] 3. Verify only DOCX and PDF documents returned

Expected: - Results include Report.docx and Budget.pdf - Results do NOT include Data.xlsx or Presentation.pptx

Pass Criteria: File type filter correctly applied at metadata filter stage


TEST-SEARCH-004: Date Range Filter#

Related: URS-Search Documents | — Risk Level: MEDIUM Type: System

Preconditions: - Test documents exist with known modification dates: - OldDoc.docx — modified 2023-01-01 - RecentDoc.docx — modified 2026-03-15

Steps: 1. Authenticate as test user 2. Send search_documents request with modified_after: "2026-01-01T00:00:00Z" 3. Verify only RecentDoc.docx returned

Expected: - Results include RecentDoc.docx - Results do NOT include OldDoc.docx

Pass Criteria: Date range filter correctly applied


TEST-SEARCH-005: Author Email Filter#

Related: URS-Search Documents | — Risk Level: MEDIUM Type: System

Preconditions: - Test documents exist: - AliceDoc.docx — created by alice@novonordisk.com - BobDoc.docx — created by bob@novonordisk.com

Steps: 1. Authenticate as test user 2. Send search_documents request with author_email: "alice@novonordisk.com" 3. Verify only AliceDoc.docx returned

Expected: - Results include AliceDoc.docx - Results do NOT include BobDoc.docx

Pass Criteria: Author email filter correctly applied


TEST-BROWSE-001: List Accessible SharePoint Sites (Whitelist Applied)#

Related: URS-Browse | RISK-R1, RISK-R4 Risk Level: HIGH Type: Integration

Preconditions: - Site whitelist configured with two allowed sites - Test user has Graph API permissions to three sites (two whitelisted, one not)

Steps: 1. Authenticate as test user 2. Send list_sites request 3. Verify only whitelisted sites returned (even though user has permissions to all three)

Expected: - Results contain two sites (both whitelisted) - Non-whitelisted site absent from results - CloudWatch logs: sites_listed event with result_count: 2

Pass Criteria: Site whitelist enforced for browse operations

Verification: RISK-R4 — Whitelist applies to both search and browse operations


TEST-BROWSE-002: Navigate Folder Hierarchy#

Related: URS-Browse | RISK-R1 Risk Level: HIGH Type: Integration

Preconditions: - Test SharePoint site with folder structure: /Shared Documents/Public/Reports/ - Test user has read permissions

Steps: 1. Authenticate as test user 2. Send list_folder request with site_id and folder_path: "" 3. Verify root-level items returned 4. Send list_folder request with folder_path: "Shared Documents/Public" 5. Verify subfolder items returned

Expected: - Step 2: Root-level files and folders returned - Step 4: Items within Public folder returned - Each item includes: id, name, type (file/folder), size, lastModifiedDateTime

Pass Criteria: Folder navigation works; user-scoped access enforced (no cross-user folder access)


TEST-READ-001: Read Document Content (Plain Text Extraction)#

Related: URS-Read Document Content | RISK-R1, RISK-R2, RISK-R3, RISK-R5 Risk Level: CRITICAL Type: System

Preconditions: - Test documents uploaded to SharePoint: - Sample.docx — contains text "Lorem ipsum dolor sit amet" - Sample.pdf — contains text "PDF test content" - Sample.xlsx — contains cell data "Row 1, Col A" - Sample.pptx — contains slide text "Slide 1 Title" - All documents labeled "General" (below sensitivity threshold)

Steps: 1. Authenticate as test user 2. Send read_document request for each test document (DOCX, PDF, XLSX, PPTX) 3. Verify response includes: - metadata object (name, size, lastModifiedDateTime, webUrl) - content field with plain text - redacted: false 4. Verify text content matches expected (no binary data, no parsing errors) 5. Check CloudWatch logs for document_read event (verify NO document content logged, only document ID and file extension)

Expected: - HTTP 200 OK for all documents - Plain text content extracted correctly for each format - No binary data in response - CloudWatch logs contain document_read events with file_extension, parse_time_ms, redacted: false, but NO filename or content fields

Pass Criteria: Document parsing succeeds for common formats; content extraction accurate; no content leakage in logs

Verification: - RISK-R2 — No document content logged to CloudWatch - RISK-R5 — Document parsing errors handled gracefully (tested in TEST-READ-002)


TEST-READ-002: Document Parsing Error Handling (Corrupted Files)#

Related: URS-Read Document Content | RISK-R5 Risk Level: MEDIUM Type: System

Preconditions: - Corrupted test documents uploaded to SharePoint: - Corrupted.docx — truncated ZIP archive (invalid DOCX structure) - Corrupted.pdf — missing PDF header - Mismatched.pdf — DOCX file renamed to .pdf (MIME type mismatch)

Steps: 1. Authenticate as test user 2. Send read_document request for each corrupted document 3. Verify error responses (not HTTP 5xx crashes) 4. Check that error messages do NOT contain binary data or document content 5. Check CloudWatch logs for document_read events with parsing errors

Expected: - HTTP 200 OK response with error message in content field: - "[Document parsing failed — file may be corrupted or unsupported format]" - No binary data returned - No raw exception stack traces exposed to user - CloudWatch logs: document_read event with parse_error: true, but NO document content

Pass Criteria: Parsing errors handled gracefully; no binary data leakage; user-friendly error messages

Verification: RISK-R5 — Robust error handling prevents partial content or binary data exposure


TEST-META-001: Retrieve Document Metadata (Sensitivity Label Included)#

Related: URS-Metadata | RISK-R1, RISK-R2 Risk Level: MEDIUM Type: Integration

Preconditions: - Test document exists: TestDoc.docx with sensitivity label "Confidential"

Steps: 1. Authenticate as test user 2. Send get_metadata request for TestDoc.docx 3. Verify response includes: - name, webUrl, size, lastModifiedDateTime, createdBy - sensitivityLabel.displayName: "Confidential" 4. Check CloudWatch logs for metadata_fetched event (verify NO filename logged, only document ID)

Expected: - HTTP 200 OK response with full metadata - Sensitivity label correctly returned - CloudWatch logs: metadata_fetched event with drive_id, item_id only (no name or title fields)

Pass Criteria: Metadata retrieval succeeds; sensitivity label available for sensitivity gate decisions; no PII logged

Verification: RISK-R2 — Metadata fields excluded from logs


TEST-SEC-SENS-001: Sensitivity Label — Public Document (Accessible)#

Related: URS-Sensitivity Labels | RISK-R3 Risk Level: CRITICAL Type: Security

Preconditions: - Sensitivity config: max_label: General - Test document: Public.docx labeled "Public" (below threshold)

Steps: 1. Authenticate as test user 2. Send read_document request for Public.docx 3. Verify full content returned, redacted: false

Expected: - HTTP 200 OK - Full plain text content in response - redacted: false

Pass Criteria: Documents below threshold accessible


TEST-SEC-SENS-002: Sensitivity Label — General Document (Accessible, At Threshold)#

Related: URS-Sensitivity Labels | RISK-R3 Risk Level: CRITICAL Type: Security

Preconditions: - Sensitivity config: max_label: General - Test document: General.docx labeled "General" (at threshold)

Steps: 1. Authenticate as test user 2. Send read_document request for General.docx 3. Verify full content returned, redacted: false

Expected: - HTTP 200 OK - Full plain text content in response - redacted: false

Pass Criteria: Documents at threshold level accessible


TEST-SEC-SENS-003: Sensitivity Label — Confidential Document (Redacted, Above Threshold)#

Related: URS-Sensitivity Labels | RISK-R3 Risk Level: CRITICAL Type: Security

Preconditions: - Sensitivity config: max_label: General - Test document: Confidential.docx labeled "Confidential" (above threshold)

Steps: 1. Authenticate as test user 2. Send read_document request for Confidential.docx 3. Verify content redacted, redacted: true 4. Verify metadata still returned (transparency)

Expected: - HTTP 200 OK - content field contains: "[REDACTED — sensitivity label exceeds configured maximum: Confidential]" - redacted: true - Metadata (name, webUrl, lastModifiedDateTime) present

Pass Criteria: Document content blocked, but metadata visible (transparency); user informed of restriction reason

Verification: RISK-R3 — Sensitivity gate blocks restricted content


TEST-SEC-SENS-004: Sensitivity Label — Unlabeled Document (Configurable Behavior)#

Related: URS-Sensitivity Labels | RISK-R3 Risk Level: CRITICAL Type: Security

Preconditions: - Sensitivity config: max_label: General, block_unlabeled: false - Test document: Unlabeled.docx with no sensitivity label

Steps: 1. Authenticate as test user 2. Send read_document request for Unlabeled.docx 3. Verify full content returned (because block_unlabeled: false) 4. Reconfigure server with block_unlabeled: true 5. Send same request again 6. Verify content now redacted

Expected: - Step 3: HTTP 200 OK, full content, redacted: false - Step 6: HTTP 200 OK, content redacted, redacted: true, message: "[REDACTED — document has no sensitivity label]"

Pass Criteria: block_unlabeled configuration correctly controls unlabeled document access

Verification: RISK-R3 — Unlabeled document handling configurable


TEST-SEC-SENS-005: Sensitivity Label — Invalid Configuration (Fail-Closed)#

Related: URS-Sensitivity Labels | RISK-R3 Risk Level: CRITICAL Type: Security

Preconditions: - Invalid sensitivity config (e.g., max_label: InvalidLabel not in known label hierarchy)

Steps: 1. Deploy SharePoint MCP server with invalid config 2. Verify server startup fails OR all document access blocked 3. Check CloudWatch logs for configuration validation error

Expected: - Server startup failure with error message: "Invalid sensitivity label configuration" - OR: Server starts but all read_document requests return error: "Sensitivity configuration invalid — access denied" - CloudWatch logs: config_validation_failed event

Pass Criteria: Invalid configuration causes fail-closed behavior (no access allowed); explicit error logged

Verification: RISK-R3 — Fail-closed default prevents misconfiguration from exposing restricted content


TEST-SEC-PERM-001: Cross-User Access Prevention#

Related: URS-Permission Enforcement | RISK-R1 Risk Level: CRITICAL Type: Security

Preconditions: - Two test users: alice@novonordisk.com, bob@novonordisk.com - Document AlicePrivate.docx in Alice's private OneDrive (Bob has NO SharePoint permissions)

Steps: 1. Authenticate as Bob 2. Send search_documents request with query matching AlicePrivate.docx 3. Verify document does NOT appear in Bob's search results 4. Attempt to send read_document request with Alice's document ID 5. Verify HTTP 403 Forbidden or empty result (Graph API rejects request)

Expected: - Search results for Bob do NOT include Alice's private document - Direct read attempt returns HTTP 403 or error message: "Access denied" - CloudWatch logs: NO documents from Alice's OneDrive listed in Bob's session

Pass Criteria: OBO authentication ensures user-scoped access; no cross-user data leakage

Verification: RISK-R1 — User-scoped permissions enforced by Graph API and OBO flow


TEST-SEC-PERM-002: Site Permissions Respected (Graph API Layer)#

Related: URS-Permission Enforcement | RISK-R1 Risk Level: HIGH Type: Security

Preconditions: - SharePoint site RestrictedSite exists - Test user has NO SharePoint read permissions to RestrictedSite - RestrictedSite NOT in site whitelist (tests Graph API layer, not just whitelist)

Steps: 1. Authenticate as test user (without permissions to RestrictedSite) 2. Send search_documents request with query matching documents in RestrictedSite 3. Verify NO results from RestrictedSite returned (Graph API rejects access)

Expected: - Search results empty OR do not include documents from RestrictedSite - Graph API returns only sites/documents user has permissions for - CloudWatch logs: graph_request event with HTTP 200 (not 403) because Graph API filters results server-side

Pass Criteria: Graph API enforces SharePoint permissions; MCP server does not bypass or escalate privileges

Verification: RISK-R1 — Secondary authorization layer at Graph API (defense in depth)


TEST-SEC-READONLY-001: Write Operations Rejected#

Related: URS-Read-Only Access | — Risk Level: HIGH Type: Security

Preconditions: - SharePoint MCP server configured with read-only scopes: Sites.Read.All, Files.Read.All (no write scopes) - Test document exists: TestDoc.docx

Steps: 1. Attempt to modify document metadata (if write tool exists, expect failure) 2. Attempt to delete document (if delete tool exists, expect failure) 3. Attempt to upload new document (if upload tool exists, expect failure) 4. Verify all write operations rejected by Graph API with HTTP 403 Forbidden

Expected: - All write operations rejected - Graph API error: "Insufficient privileges to complete the operation" - MCP server does NOT escalate privileges or use service account for writes

Pass Criteria: No write operations possible; read-only scopes enforced

Verification: Scoped permissions reduce blast radius (RISK-R1)


TEST-SEC-PERSIST-001: No Document Content Persisted#

Related: URS-Data Retention | RISK-R2 Risk Level: HIGH Type: Security

Preconditions: - SharePoint MCP server running with DynamoDB table for token storage - Test document retrieved via read_document

Steps: 1. Authenticate as test user 2. Send read_document request for test document 3. Verify response contains document content 4. Query DynamoDB table for all items (use AWS CLI or console) 5. Verify NO document content, filenames, or metadata stored in DynamoDB 6. Verify only OAuth tokens (access_token, refresh_token, expires_at) present

Expected: - DynamoDB table contains user tokens only - No content, filename, title, author, or webUrl fields in DynamoDB - CloudWatch logs confirm stateless HTTP mode: stateless_http: true

Pass Criteria: Document content never persisted; only OAuth tokens cached in DynamoDB

Verification: RISK-R2 — No data persistence for SharePoint content


TEST-SEC-WHITELIST-001: Whitelist Enforcement — Allowed Site#

Related: Site Whitelist | RISK-R4 Risk Level: CRITICAL Type: Security

Preconditions: - Site whitelist configured: ["https://novonordisk.sharepoint.com/sites/AllowedSite"] - Test document exists in AllowedSite

Steps: 1. Authenticate as test user 2. Send search_documents request matching document in AllowedSite 3. Verify document appears in results

Expected: - HTTP 200 OK - Document from AllowedSite present in results

Pass Criteria: Whitelisted sites accessible


TEST-SEC-WHITELIST-002: Whitelist Enforcement — Blocked Site#

Related: Site Whitelist | RISK-R4 Risk Level: CRITICAL Type: Security

Preconditions: - Site whitelist configured: ["https://novonordisk.sharepoint.com/sites/AllowedSite"] - Test document exists in BlockedSite (not in whitelist) - Test user has Graph API read permissions to BlockedSite (verifies whitelist enforced at app layer)

Steps: 1. Authenticate as test user 2. Send search_documents request matching document in BlockedSite 3. Verify document does NOT appear in results (filtered out by whitelist) 4. Check CloudWatch logs for whitelist_filter_applied event

Expected: - HTTP 200 OK response - Results do NOT include document from BlockedSite - CloudWatch logs: whitelist_filter_applied event with dropped_count: 1

Pass Criteria: Non-whitelisted sites blocked even if user has Graph API permissions

Verification: RISK-R4 — Whitelist enforced at application layer (defense in depth)


TEST-SEC-WHITELIST-003: Empty Whitelist — Fail-Closed#

Related: Site Whitelist | RISK-R4 Risk Level: CRITICAL Type: Security

Preconditions: - Site whitelist configured as empty list: []

Steps: 1. Authenticate as test user 2. Send list_sites request 3. Verify NO sites returned (all blocked) 4. Send search_documents request 5. Verify NO results returned (all filtered out)

Expected: - list_sites returns empty list - search_documents returns empty results - CloudWatch logs: whitelist_filter_applied with dropped_count: all

Pass Criteria: Empty whitelist blocks all access (fail-closed behavior)

Verification: RISK-R4 — Default behavior prevents overly broad access


TEST-SEC-LOGS-001: CloudWatch Logs — No Document Content#

Related: Logging Privacy | RISK-R2 Risk Level: HIGH Type: Security

Preconditions: - Test document retrieved via read_document

Steps: 1. Authenticate as test user 2. Send read_document request for test document containing text "CONFIDENTIAL_DATA_MARKER" 3. Retrieve CloudWatch logs for the request 4. Search logs for string "CONFIDENTIAL_DATA_MARKER" 5. Verify string does NOT appear in logs

Expected: - CloudWatch logs contain document_read event with drive_id, item_id, file_extension, parse_time_ms, redacted (bool) - Logs do NOT contain content, filename, title, or any document text

Pass Criteria: Document content excluded from logs

Verification: RISK-R2 — Structured logging with field exclusion prevents content leakage


TEST-SEC-LOGS-002: CloudWatch Logs — No Search Query Text#

Related: Logging Privacy | RISK-R7 Risk Level: HIGH Type: Security

Preconditions: - Test query executed via search_documents

Steps: 1. Authenticate as test user 2. Send search_documents request with query: "SECRET_QUERY_MARKER" 3. Retrieve CloudWatch logs for the request 4. Search logs for string "SECRET_QUERY_MARKER" 5. Verify string does NOT appear in logs

Expected: - CloudWatch logs contain documents_searched event with user_id, result_count, filter_stats, but NO query field - Query text not logged (only query ID or result metadata)

Pass Criteria: Query text excluded from logs

Verification: RISK-R7 — User intent and sensitive search queries not logged


Security Tests#

TEST-SEC-001: Token Expiration Enforcement#

Tool: Manual testing with expired tokens Expected: All expired tokens rejected with HTTP 401 before Graph API calls Pass: Zero data access with expired token Verification: RISK-R1 (covered by TEST-AUTH-002)

TEST-SEC-002: OAuth Scope Validation#

Tool: Azure AD app registration audit + manual token inspection (JWT decode) Expected: Token scopes limited to Sites.Read.All, Files.Read.All, offline_access only Pass: No write scopes present; write operations rejected by Graph API Verification: RISK-R1

TEST-SEC-003: TLS Encryption#

Tool: SSL Labs scan of production endpoint (sharepoint.connectors.novo-genai.com) Expected: TLS 1.2+ only, no weak ciphers, grade A or higher Pass: TLS properly configured at ALB layer Verification: RISK-R1 (token encryption in transit)

TEST-SEC-004: DynamoDB Encryption at Rest#

Tool: AWS Console / Terraform state inspection Expected: DynamoDB table encrypted with AWS KMS customer-managed key Pass: Encryption confirmed via AWS console Verification: Token storage security

TEST-SEC-005: CloudWatch Log Encryption#

Tool: AWS Console / Terraform state inspection Expected: CloudWatch log group encrypted with AWS KMS Pass: Encryption enabled with KMS key Verification: RISK-R2 (log security)


Quality Gates#

Before production deployment: - [ ] All CRITICAL test cases passed (TEST-AUTH-001, TEST-AUTH-002, TEST-SEARCH-002, TEST-READ-001, TEST-SEC-SENS-001 to 005, TEST-SEC-PERM-001, TEST-SEC-WHITELIST-001 to 003) - [ ] All HIGH risk test cases passed (TEST-SEARCH-001, TEST-BROWSE-001, TEST-BROWSE-002, TEST-SEC-PERM-002, TEST-SEC-READONLY-001, TEST-SEC-PERSIST-001, TEST-SEC-LOGS-001, TEST-SEC-LOGS-002) - [ ] Zero critical defects open - [ ] < 3 medium defects open (accepted, must be documented with mitigation plans) - [ ] Security scan passed (OWASP ZAP or equivalent, no HIGH/CRITICAL findings) - [ ] CloudWatch logs reviewed for PII/content leakage (manual inspection of 50+ request samples) - [ ] Sensitivity label configuration validated against organizational policy - [ ] Site whitelist configuration validated by business owner - [ ] OAuth2 consent screen reviewed and approved by legal/compliance - [ ] Production deployment checklist signed off


Test Environment#

Dev: https://sharepoint.dev.connectors.novo-genai.com - AWS Account: 094069622854 (AWS-NN-AIconnectors-DEV) - ECS Cluster: aiconnectors-dev - Log Level: DEBUG (for detailed debugging during development) - Token Storage: Memory-based (no DynamoDB dependency) - Test Data: Synthetic SharePoint sites and documents created via Graph API

Staging: Dev endpoint with production-like configuration - Sensitivity label config loaded from production SSM parameters - Site whitelist matches production whitelist - Log level: INFO (production-like) - Token storage: DynamoDB (separate dev table)

Prod: https://sharepoint.connectors.novo-genai.com - AWS Account: 673034950531 (AWS-NN-AIconnectors-PRD) - ECS Cluster: aiconnectors-prod - Log Level: INFO - Token Storage: DynamoDB table mcp-oauth-storage-sharepoint-mcp-prod - Access: Production Azure AD tenant, production SharePoint sites

Test Users: - testuser-sharepoint-mcp@novonordisk.com — standard user with read access to test sites - testuser-restricted@novonordisk.com — user with limited SharePoint permissions (for cross-user access tests) - testuser-admin@novonordisk.com — user with broad SharePoint access (for whitelist bypass testing)

Test SharePoint Sites: - https://novonordisk.sharepoint.com/sites/TestSite1 — whitelisted, test documents present - https://novonordisk.sharepoint.com/sites/TestSite2 — whitelisted, test documents present - https://novonordisk.sharepoint.com/sites/RestrictedSite — NOT whitelisted, test documents present (verifies whitelist enforcement)

Test Documents: - Public.docx — sensitivity label "Public" - General.docx — sensitivity label "General" - Confidential.docx — sensitivity label "Confidential" (above threshold) - Unlabeled.docx — no sensitivity label - Sample.pdf, Sample.xlsx, Sample.pptx — document parsing tests - Corrupted.docx, Corrupted.pdf — error handling tests


Acceptance Criteria#

This Installation Validation is considered complete and successful when:

  1. 100% of CRITICAL and HIGH risk test cases passed (blocking gate)
  2. All RISK-R1 to RISK-R7 verification points confirmed via test evidence
  3. CloudWatch logs reviewed for 50+ real user requests (post-deployment smoke test) — zero PII/content leakage found
  4. Sensitivity label configuration validated by business owner and matches organizational policy
  5. Site whitelist configuration validated by business owner and limits access to approved sites only
  6. OAuth2 consent screen reviewed and approved by legal/compliance team
  7. Production deployment checklist signed off by Product Owner, Engineering Lead, and Security Lead
  8. Residual risks documented and accepted by risk owner (see RISK:SharePointAccess residual risk section)

Sign-off: - QA Lead: __ Date: __ - Security Lead: ___ Date: ___ - Product Owner: __ Date: ______


Version: 1.0 Date: 2026-04-22 Author: AI Connectors QA Team Next Review: 2026-10-22 (6 months, or upon major feature changes)