sync: auto-sync from GURU-5070 at 2026-07-06 13:43:08
Author: Mike Swanson Machine: GURU-5070 Timestamp: 2026-07-06 13:43:08
This commit is contained in:
@@ -218,3 +218,4 @@
|
|||||||
- [Claude tui fullscreen crash](feedback_claude_tui_fullscreen_crash.md) — "flicker-free" prompt writes tui=fullscreen; instant-exit crash loop on some Windows terminals; set tui=default (reinstall does NOT fix)
|
- [Claude tui fullscreen crash](feedback_claude_tui_fullscreen_crash.md) — "flicker-free" prompt writes tui=fullscreen; instant-exit crash loop on some Windows terminals; set tui=default (reinstall does NOT fix)
|
||||||
- [Backup targets never guessed](feedback_backup_targets_never_guessed.md) — billed-vs-running mismatches are billing questions for Mike/Winter; never infer/deploy backup targets
|
- [Backup targets never guessed](feedback_backup_targets_never_guessed.md) — billed-vs-running mismatches are billing questions for Mike/Winter; never infer/deploy backup targets
|
||||||
- [Fire #dev-alerts for client/RMM work](feedback_fire_dev_alerts_for_client_work.md) — Howard+Mike watch #dev-alerts Discord for live visibility into what techs/sessions touch. Fire post-bot-alert.sh ([DEV]/[RMM]/[DEPLOY]/[GURURMM] prefix -> #dev-alerts) at the START of any RMM/Dev or active-client-machine action. No CLAUDE.md rule yet — this memory is the rule.
|
- [Fire #dev-alerts for client/RMM work](feedback_fire_dev_alerts_for_client_work.md) — Howard+Mike watch #dev-alerts Discord for live visibility into what techs/sessions touch. Fire post-bot-alert.sh ([DEV]/[RMM]/[DEPLOY]/[GURURMM] prefix -> #dev-alerts) at the START of any RMM/Dev or active-client-machine action. No CLAUDE.md rule yet — this memory is the rule.
|
||||||
|
- [M365 app: SharePoint needs CERT](reference_m365_app_sharepoint_rest_vs_graph.md) — SP app-only works via the CERT (get-token.sh <tenant> sharepoint); the secret gives "Unsupported app only token". Graph app-only uses the secret.
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
---
|
||||||
|
name: reference_m365_app_sharepoint_rest_vs_graph
|
||||||
|
description: ComputerGuru M365 app suite — SharePoint app-only WORKS but requires the CERT (client_assertion), not the secret. Secret => "Unsupported app only token". Use get-token.sh <tenant> sharepoint.
|
||||||
|
metadata:
|
||||||
|
type: reference
|
||||||
|
---
|
||||||
|
|
||||||
|
The ACG **Tenant Admin app** (`709e6eed-0711-4875-9c44-2d3518c47063`) has **full SharePoint app-only
|
||||||
|
access** — `Sites.FullControl.All` on the SharePoint resource — but it is gated by an auth-method rule
|
||||||
|
that keeps biting:
|
||||||
|
|
||||||
|
- **SharePoint app-only REQUIRES a CERTIFICATE (client_assertion). A `client_secret` token is rejected**
|
||||||
|
with **`Unsupported app only token`** on EVERY SharePoint endpoint (REST `/_api/...` and CSOM
|
||||||
|
`/_vti_bin/client.svc/ProcessQuery`). This is a SharePoint platform rule, not a missing grant.
|
||||||
|
- **Graph** app-only accepts the secret fine — so Graph SharePoint calls (driveItem `createdBy`/
|
||||||
|
`lastModifiedBy`/`retentionLabel`, item `/permissions` + inheritance, `/groups` + members) work with
|
||||||
|
the secret and are the right tool for *investigation*.
|
||||||
|
|
||||||
|
**Do NOT hand-roll a SharePoint token from the secret. Use the remediation-tool cert tiers:**
|
||||||
|
```bash
|
||||||
|
cd .claude/skills/remediation-tool
|
||||||
|
bash scripts/get-token.sh <tenant> sharepoint # content resource <name>.sharepoint.com (cert)
|
||||||
|
bash scripts/get-token.sh <tenant> sharepoint-admin # admin resource <name>-admin.sharepoint.com (cert)
|
||||||
|
```
|
||||||
|
`get-token.sh` forces cert for the `sharepoint*` tiers automatically; the minted token's `roles` =
|
||||||
|
`["Sites.FullControl.All"]`. The cert is vaulted in `msp-tools/computerguru-tenant-admin.sops.yaml`
|
||||||
|
(`cert_thumbprint_b64url` + `cert_private_key_pem_b64`). Tenant arg = the domain (`birthbiologic.com`).
|
||||||
|
|
||||||
|
**Use the CERT (SP REST/CSOM) for:** list settings (`ForceCheckout`, `EnableModeration`/content approval,
|
||||||
|
versioning), per-item `CheckoutUserId`/checkout state, re-stamping `Author`/`Editor` (Created By /
|
||||||
|
Modified By), site lock, tenant settings. Graph can't do these.
|
||||||
|
|
||||||
|
Reference (authoritative): `.claude/skills/remediation-tool/references/app-permissions-and-sharepoint.md`
|
||||||
|
and `app-suite.md`. **Before ever telling the user "the tool can't do X" on SharePoint, use the cert
|
||||||
|
tier and verify** — the "Unsupported app only token" wall means *wrong auth method (secret)*, NOT no access.
|
||||||
|
See [[birth-biologic]] (migrated content owned by "SharePoint App" => greyed-out Move; fix = re-stamp
|
||||||
|
Author/Editor via cert CSOM `SystemUpdate`). Open question (Mike, 2026-07-06): standardize ALL M365
|
||||||
|
app-only auth on cert (cert is resource-agnostic + more secure) to kill this secret-vs-cert friction.
|
||||||
@@ -0,0 +1,105 @@
|
|||||||
|
## User
|
||||||
|
- **User:** Mike Swanson (mike)
|
||||||
|
- **Machine:** GURU-5070
|
||||||
|
- **Role:** admin
|
||||||
|
|
||||||
|
## Session Summary
|
||||||
|
|
||||||
|
Birth Biologic reported (warranty) that users "can no longer move files within SharePoint" — Move/Copy
|
||||||
|
options greyed out and drag-drop silently failing. Investigated the migrated Quality library and
|
||||||
|
confirmed Mike's hypothesis: **every migrated folder/file is authored by `SharePoint App`** (the app-only
|
||||||
|
service principal that ran the Datto->SharePoint Graph/SPMT uploads) — there is no human owner on any of
|
||||||
|
it. By contrast, a folder a real user created (`Quality General`, author **Julie Beck**) is normal and
|
||||||
|
movable. This is the whole problem: SharePoint disables Move/Copy/Rename on items whose author is a
|
||||||
|
system/app account, so users can manage their own content but not the app-migrated content.
|
||||||
|
|
||||||
|
Ruled out the other candidate causes via Graph and (once authenticated correctly) SharePoint REST:
|
||||||
|
**no retention/records labels** on the items; **library `ForceCheckout=false`** and **`EnableModeration=false`**
|
||||||
|
(no require-checkout, no content approval); **no files checked out** (`CheckoutUserId` null on all sampled
|
||||||
|
items); and **inheritance is intact** with the **Members group granted `write`** — the Quality staff (Julie
|
||||||
|
Beck, Brandy Burgess, Mary Ster, Vicki Fountain, Alicia Meneely, Kristin Steen + sysadmin/operations) are
|
||||||
|
all Members, so they *have* Edit. That leaves the app authorship as the sole cause.
|
||||||
|
|
||||||
|
The investigation stalled twice on SharePoint access before landing on the correct method. Using the
|
||||||
|
Tenant Admin app's **client_secret** against SharePoint REST returned `Unsupported app only token`; I
|
||||||
|
initially (wrongly) concluded app-only SP REST was blocked and wrote a memory saying to fall back to
|
||||||
|
delegated/PnP. Mike corrected this: the app suite has a dedicated SharePoint tier — SharePoint app-only
|
||||||
|
**requires the certificate, not the secret**. Minting via `get-token.sh birthbiologic.com sharepoint`
|
||||||
|
produced a cert token with `roles=["Sites.FullControl.All"]` and SP REST worked immediately. Rewrote the
|
||||||
|
memory to the correct cert-based guidance.
|
||||||
|
|
||||||
|
The fix was scoped but not yet executed (awaiting Mike's go + target-owner decision): re-stamp
|
||||||
|
`Author`/`Editor` on the app-owned items to a real user via cert-based CSOM `SystemUpdate` (SystemUpdate
|
||||||
|
so it does not bump Modified dates — matters for a QMS/compliance library), test on one folder, have a
|
||||||
|
Quality user confirm Move works, then run across all migrated libraries (Quality, Admin, Donor Services,
|
||||||
|
Supply — all migrated the same way, so all affected). Mike also raised standardizing all M365 app-only
|
||||||
|
auth on cert (recommended — cert is resource-agnostic and kills the secret-vs-cert friction).
|
||||||
|
|
||||||
|
## Key Decisions
|
||||||
|
|
||||||
|
- **Diagnosis = app/System-Account authorship**, not permissions/checkout/retention — all three ruled out
|
||||||
|
with live data; the `SharePoint App` vs `Julie Beck` author contrast is the tell.
|
||||||
|
- **Fix via CSOM `SystemUpdate`** (not a plain REST MERGE) to preserve Modified dates on QMS records.
|
||||||
|
- **Do not bulk-run yet** — test-on-one + user confirmation first; this is a live client library.
|
||||||
|
- **Recommend cert-only for all M365 app-only tasks** — a cert works for Graph/EXO too, is MS best
|
||||||
|
practice, and removes the secret-vs-cert branching that wasted time this session.
|
||||||
|
|
||||||
|
## Problems Encountered
|
||||||
|
|
||||||
|
- **Used the client_secret for SharePoint** -> `Unsupported app only token`; wrongly concluded "no app-only
|
||||||
|
SP access" and wrote a misleading memory. Correct method: the **cert** tier via
|
||||||
|
`get-token.sh <tenant> sharepoint` (`Sites.FullControl.All`). Memory rewritten; logged as a correction.
|
||||||
|
- **Group lookup by `Quality Systems Department` returned empty first** because I filtered on an assumed
|
||||||
|
rename; the group is still named `Quality Systems Department`. Re-queried with `startswith(displayName,'Quality')`.
|
||||||
|
- **`/tmp` path tripped the block-tmp-path hook** on a Bash call (Git-Bash `/tmp` mismatch); reran with a
|
||||||
|
scratchpad path.
|
||||||
|
|
||||||
|
## Configuration Changes
|
||||||
|
|
||||||
|
- No changes to the BirthBio tenant/SharePoint yet (investigation only; the re-author fix is pending go).
|
||||||
|
- Repo: rewrote `.claude/memory/reference_m365_app_sharepoint_rest_vs_graph.md` (secret->cert correction) +
|
||||||
|
updated its `MEMORY.md` index line. Added this session log. (BUG-024/musl log from earlier today is separate.)
|
||||||
|
|
||||||
|
## Credentials & Secrets
|
||||||
|
|
||||||
|
- No new secrets. SharePoint access = **Tenant Admin app CERT** (vault `msp-tools/computerguru-tenant-admin.sops.yaml`:
|
||||||
|
`cert_thumbprint_b64url` + `cert_private_key_pem_b64`), minted by remediation-tool `get-token.sh <tenant> sharepoint`.
|
||||||
|
The app's `client_secret` (same entry) is Graph/EXO only — rejected by SharePoint.
|
||||||
|
- **Gap flagged:** BirthBio's `sysadmin@birthbiologic.com` **M365** password is NOT in the SOPS vault (only the
|
||||||
|
Google Workspace one is, `clients/birth-biologic/google-workspace.sops.yaml`). Mike says the M365 sysadmin
|
||||||
|
creds are in **1Password** for BirthBio. Not needed for the fix (cert tier suffices), but worth vaulting.
|
||||||
|
|
||||||
|
## Infrastructure & Servers
|
||||||
|
|
||||||
|
- **Tenant:** birthbiologic.com / `19a568e8-9e88-413b-9341-cbc224b39145`.
|
||||||
|
- **Tenant Admin app:** `709e6eed-0711-4875-9c44-2d3518c47063` (secret = Graph/EXO; CERT = SharePoint `Sites.FullControl.All`).
|
||||||
|
- **QSD site:** `https://birthbiologic.sharepoint.com/sites/QualitySystemsDepartment`; site id `3173c017-58bd-406a-8858-2c969667336f`;
|
||||||
|
drive `b!F8BzMb1YakCIWCyWlmczb09LHqtxDxVMpLT6kAwYmsM7NUY4oPLSRq7ng3tJq-E9`.
|
||||||
|
- **QSD M365 group:** `QualitySystemsDepartment@birthbiologic.com`, id `166dbc15-f60b-4dfc-9581-236980032da4`;
|
||||||
|
Members (=site Edit): sysadmin, Julie Beck, Brandy Burgess, Mary Ster, Vicki Fountain, Alicia Meneely, Kristin Steen, Operations.
|
||||||
|
- **Documents library:** `ForceCheckout=false`, `EnableModeration=false`, `EnableVersioning=true`, `EnableMinorVersions=false`.
|
||||||
|
|
||||||
|
## Commands & Outputs
|
||||||
|
|
||||||
|
- Mint SP cert token: `cd .claude/skills/remediation-tool && bash scripts/get-token.sh birthbiologic.com sharepoint`
|
||||||
|
-> token roles `["Sites.FullControl.All"]`. (`sharepoint-admin` tier = the `-admin.sharepoint.com` resource.)
|
||||||
|
- Ownership (Graph): `GET /drives/{drive}/root/children?$select=name,createdBy,lastModifiedBy` -> all `SharePoint App`.
|
||||||
|
- Author contrast (SP REST): `GET .../lists/getbytitle('Documents')/items?$select=FileLeafRef,CheckoutUserId,Author/Title,Editor/Title&$expand=Author,Editor`
|
||||||
|
-> migrated = `SharePoint App`, `Quality General` = `Julie Beck`; `CheckoutUserId` null throughout.
|
||||||
|
- Secret-vs-cert: SP REST with the **secret** token -> `Unsupported app only token`; with the **cert** token -> works.
|
||||||
|
|
||||||
|
## Pending / Incomplete Tasks
|
||||||
|
|
||||||
|
- **Execute the fix (warranty):** re-stamp `Author`/`Editor` on app-owned items to a real user via cert CSOM
|
||||||
|
`SystemUpdate`. **Decision needed from Mike:** target owner (`sysadmin@` neutral, or a Quality lead like
|
||||||
|
Julie/Brandy). Test one folder -> Quality user confirms Move -> bulk across Quality, Admin, Donor Services, Supply.
|
||||||
|
- **Cert-only standardization (follow-up):** switch `get-token.sh` to cert-first for every tier; register the
|
||||||
|
cert on any secret-only apps; retire secrets. Prevents this recurring.
|
||||||
|
- **Vault the BirthBio `sysadmin@` M365 password** (currently only in 1Password).
|
||||||
|
|
||||||
|
## Reference Information
|
||||||
|
|
||||||
|
- Authoritative SP access doc: `.claude/skills/remediation-tool/references/app-permissions-and-sharepoint.md` + `app-suite.md`.
|
||||||
|
- Memory: `.claude/memory/reference_m365_app_sharepoint_rest_vs_graph.md` (corrected to cert).
|
||||||
|
- Wiki: `wiki/clients/birth-biologic.md` (File Storage / SharePoint Site Map; QSD site+drive IDs already recorded there).
|
||||||
|
- Symptom class: greyed-out Move/Copy/Rename + silent drag-drop fail on items authored by `SharePoint App`/`System Account`.
|
||||||
@@ -19,6 +19,8 @@ Categories (the `[type]` tag): _(none)_ = skill/command execution failure ·
|
|||||||
|
|
||||||
<!-- Append entries below this line -->
|
<!-- Append entries below this line -->
|
||||||
|
|
||||||
|
2026-07-06 | GURU-5070 | remediation-tool/sharepoint | [correction] assumed SP REST app-only was blocked ('Unsupported app only token') and to use delegated/PnP; correct is the app suite has a CERT-based sharepoint tier — get-token.sh <tenant> sharepoint mints a cert token with Sites.FullControl.All. Secret is Graph/EXO only. [ctx: client=birth-biologic ref=reference_m365_app_sharepoint_rest_vs_graph]
|
||||||
|
|
||||||
2026-07-06 | GURU-5070 | wiki-compile | [correction] ran --full (Sonnet rebuild) for a routine post-work capture; plain /wiki-compile client:<slug> (update mode) is the fast incremental path for 'just did work, capture it' — reserve --full for structural drift/clean rebuilds
|
2026-07-06 | GURU-5070 | wiki-compile | [correction] ran --full (Sonnet rebuild) for a routine post-work capture; plain /wiki-compile client:<slug> (update mode) is the fast incremental path for 'just did work, capture it' — reserve --full for structural drift/clean rebuilds
|
||||||
|
|
||||||
2026-07-06 | GURU-5070 | dev-alerts/visibility | [correction] did substantial RMM/Dev + live-client-machine work (Lonestar Unraid boot-config edits, service cycling, v0.6.77 deploy, promotions) WITHOUT firing #dev-alerts; Howard+Mike lost live visibility. Fire post-bot-alert.sh at the START of such work. [ctx: ref=feedback_fire_dev_alerts_for_client_work]
|
2026-07-06 | GURU-5070 | dev-alerts/visibility | [correction] did substantial RMM/Dev + live-client-machine work (Lonestar Unraid boot-config edits, service cycling, v0.6.77 deploy, promotions) WITHOUT firing #dev-alerts; Howard+Mike lost live visibility. Fire post-bot-alert.sh at the START of such work. [ctx: ref=feedback_fire_dev_alerts_for_client_work]
|
||||||
|
|||||||
@@ -168,7 +168,7 @@ Site IDs hardcoded in `$SITE_MAP` hashtable in the migration script. QSD site ID
|
|||||||
- **SharePoint 409 Conflict on retry:** If a chunked upload session is interrupted, a partial item remains in SharePoint. Subsequent upload sessions against the same path return 409 Conflict. Fix: DELETE the item before creating a new upload session.
|
- **SharePoint 409 Conflict on retry:** If a chunked upload session is interrupted, a partial item remains in SharePoint. Subsequent upload sessions against the same path return 409 Conflict. Fix: DELETE the item before creating a new upload session.
|
||||||
- **Long Windows paths (>260 chars) require `\\?\` prefix:** The Datto source tree contains paths exceeding MAX_PATH. Use `\\?\` prefix for `[IO.File]` reads in PowerShell. Note: `Rename-Item` and `File.Move` in PS5.1 do NOT support `\\?\` — use `robocopy` or SPMT for long-path rename/move operations.
|
- **Long Windows paths (>260 chars) require `\\?\` prefix:** The Datto source tree contains paths exceeding MAX_PATH. Use `\\?\` prefix for `[IO.File]` reads in PowerShell. Note: `Rename-Item` and `File.Move` in PS5.1 do NOT support `\\?\` — use `robocopy` or SPMT for long-path rename/move operations.
|
||||||
- **SharePoint single-session upload throttles ~40 Mbps:** For large migrations, parallel-stream uploaders (multiple concurrent file uploads, larger chunk sizes) would significantly improve throughput.
|
- **SharePoint single-session upload throttles ~40 Mbps:** For large migrations, parallel-stream uploaders (multiple concurrent file uploads, larger chunk sizes) would significantly improve throughput.
|
||||||
- **Tenant Admin app cannot delete M365 groups (403):** The Tenant Admin app has GroupMember write only, not Group.ReadWrite.All. `DELETE /groups/{id}` returns 403 via Tenant Admin app. Use the **User Manager app** for group deletes (returns HTTP 204). Also: the Tenant Admin app cannot manage SP site lock/spoke-site grants (`Unsupported app only token` on SP REST) — use PnP PowerShell as SharePoint Admin.
|
- **Tenant Admin app cannot delete M365 groups (403):** The Tenant Admin app has GroupMember write only, not Group.ReadWrite.All. `DELETE /groups/{id}` returns 403 via Tenant Admin app. Use the **User Manager app** for group deletes (returns HTTP 204). Also: **SharePoint app-only REST/CSOM requires the Tenant Admin app's CERTIFICATE, not the secret** — a `client_secret` token returns `Unsupported app only token` on every SP endpoint. Mint the cert token via `get-token.sh <tenant> sharepoint` (roles `Sites.FullControl.All`); do NOT reach for the secret or conclude "no SP access" (corrected 2026-07-06; the earlier "use PnP" note was wrong — the cert tier works app-only).
|
||||||
- **Byte-array stringification bug — RETIRED path:** The 2026-06-26 custom-script upload path passed file bytes as `"$bytes"`, which stringified the .NET byte array to space-separated decimal text instead of raw binary. Corrupt files are inflated ~3-4x; headers are decimal (e.g. `80 75 3 4...` for PK, `37 80 68 70...` for %PDF). 84 files were corrupted and restored from Datto source. This code path is permanently retired. **Never stringify a byte array in PowerShell** — use `[IO.File]::WriteAllBytes` for binary output.
|
- **Byte-array stringification bug — RETIRED path:** The 2026-06-26 custom-script upload path passed file bytes as `"$bytes"`, which stringified the .NET byte array to space-separated decimal text instead of raw binary. Corrupt files are inflated ~3-4x; headers are decimal (e.g. `80 75 3 4...` for PK, `37 80 68 70...` for %PDF). 84 files were corrupted and restored from Datto source. This code path is permanently retired. **Never stringify a byte array in PowerShell** — use `[IO.File]::WriteAllBytes` for binary output.
|
||||||
- **SPMT requires sysadmin to be SharePoint admin:** SPMT destination access requires the running account to have SharePoint admin rights. Confirm before scheduling future SPMT runs.
|
- **SPMT requires sysadmin to be SharePoint admin:** SPMT destination access requires the running account to have SharePoint admin rights. Confirm before scheduling future SPMT runs.
|
||||||
- **Syncro comment rendering:** Use `<br>` for line breaks in Syncro comments. `<ul>/<li>` collapses into a single line in the Syncro renderer.
|
- **Syncro comment rendering:** Use `<br>` for line breaks in Syncro comments. `<ul>/<li>` collapses into a single line in the Syncro renderer.
|
||||||
@@ -185,6 +185,7 @@ Site IDs hardcoded in `$SITE_MAP` hashtable in the migration script. QSD site ID
|
|||||||
- **Tenant's real Business Premium skuId is `cbdc14ab-d96c-4c30-b9f4-6ada7cdc1d46`:** The scope doc had a stale GUID (`cbdc14ab-d96c-4132-b7f4-1f3a3a819bb4`). License assign 400'd until corrected. Pull skuId live from Graph `/subscribedSkus` before any license assignment.
|
- **Tenant's real Business Premium skuId is `cbdc14ab-d96c-4c30-b9f4-6ada7cdc1d46`:** The scope doc had a stale GUID (`cbdc14ab-d96c-4132-b7f4-1f3a3a819bb4`). License assign 400'd until corrected. Pull skuId live from Graph `/subscribedSkus` before any license assignment.
|
||||||
- **Datto→SharePoint additive push caused "reappearing files":** The April 2026 SPMT/script run was additive (never a live sync). Files deleted from Datto after April remained in SharePoint, creating phantom files that appeared to "reappear." Resolved 2026-06-27 by treating Datto as source of truth and mirroring SP to it (deleted 1,564 stale SP files to recycle bin). SharePoint and Datto are now synchronized.
|
- **Datto→SharePoint additive push caused "reappearing files":** The April 2026 SPMT/script run was additive (never a live sync). Files deleted from Datto after April remained in SharePoint, creating phantom files that appeared to "reappear." Resolved 2026-06-27 by treating Datto as source of truth and mirroring SP to it (deleted 1,564 stale SP files to recycle bin). SharePoint and Datto are now synchronized.
|
||||||
- **Quality content two-site confusion:** A `Quality Department` site (/sites/QualityDepartment) was the original April 2026 migration landing target; `Quality Systems Department` (/sites/QualitySystemsDepartment) was created 2026-06-02 as the canonical site. The old site was soft-deleted 2026-06-29 after content parity was verified and the one divergent file was preserved in QSD. Do not expect /sites/QualityDepartment to exist after ~2026-09-29 (recycle bin expiry).
|
- **Quality content two-site confusion:** A `Quality Department` site (/sites/QualityDepartment) was the original April 2026 migration landing target; `Quality Systems Department` (/sites/QualitySystemsDepartment) was created 2026-06-02 as the canonical site. The old site was soft-deleted 2026-06-29 after content parity was verified and the one divergent file was preserved in QSD. Do not expect /sites/QualityDepartment to exist after ~2026-09-29 (recycle bin expiry).
|
||||||
|
- **Migrated content owned by `SharePoint App` -> users get greyed-out Move/Copy/Rename (2026-07-06, warranty):** Everything migrated into SharePoint via the app-only Graph/SPMT uploads is authored by `SharePoint App` (no human owner). SharePoint disables Move/Copy/Rename + silently fails drag-drop on system/app-authored items, so users can move their *own* content but not the migrated tree — confirmed by contrast: `Quality General` (author Julie Beck) moves fine; every migrated folder (author `SharePoint App`) does not. NOT a permissions gap (Members group has `write`, inheritance intact, staff are all Members), NOT checkout (`ForceCheckout=false`, `CheckoutUserId` null), NOT retention (no labels). **Fix:** re-stamp `Author`/`Editor` to a real user via cert-token CSOM `SystemUpdate` (SystemUpdate preserves Modified dates — matters for the QMS). Affects ALL migrated libraries (Quality, Admin, Donor Services, Supply — same upload path). Diagnosed via the cert `sharepoint` tier (see the SharePoint cert note above).
|
||||||
|
|
||||||
## Active Work
|
## Active Work
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user