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