sync: auto-sync from GURU-BEAST-ROG at 2026-06-02 10:44:23

Author: Mike Swanson
Machine: GURU-BEAST-ROG
Timestamp: 2026-06-02 10:44:23
This commit is contained in:
2026-06-02 10:44:27 -07:00
parent df8c144791
commit 61081f70c2
8 changed files with 309 additions and 14 deletions

View File

@@ -48,6 +48,7 @@
- [Paste-safe command formatting (Howard)](feedback_command_formatting.md) — Two clauses, one root cause: (a) multi-line scripts not semicolon one-liners (wrap breaks paste), (b) all code at column 0 inside fences (indentation breaks PowerShell paste).
- [Autonomous infra/build setup](feedback_autonomous_infra_setup.md) — During infra/build/CI/dev setup, just install prerequisites and push through routine steps; reserve check-ins for genuine decisions (forks, destructive/outward, client/prod).
- [Check patterns before asking](feedback_check_patterns_before_asking.md) — Before asking how to do something repeat-style (sync, save, sweep, billing), study existing artifacts and workflow docs first; reach for similar past artifacts as the template.
- [Pricing verification — no guessing](policy_pricing_verification.md) — ANY cost presented to the team or a client MUST be verified via live web lookup (WebFetch/WebSearch, fallback to headless Chrome). Never estimate from training data. Cite source + date inline. If unreachable, say so — do NOT substitute a guess.
- [Client communication tone](feedback_client_tone.md) — How to write client-facing Syncro comments — expert partner, not intake questionnaire.
- [Add Mike as owner on all Entra apps](feedback_entra_app_owner.md) — Apps created via management SP have no user owner — must add Mike manually or publisher verification fails.
- [No TOML/config file approach for endpoints](feedback_no_toml_config_endpoints.md) — User explicitly prohibits TOML or config-file-based endpoint configuration — this will never be approved.

View File

@@ -0,0 +1,30 @@
# Policy: Pricing Verification — No Guessing
**Set by:** Mike Swanson, 2026-06-02
Any time a cost or price is presented to the team or a client, it MUST be verified via a
live web lookup before being stated. Never use training-data recollections or estimates.
## Rules
- Hardware, parts, software licensing, SaaS pricing, labor rates — all require real-time verification.
- Use WebFetch / WebSearch first. Fall back to headless Chrome (`web-fetch-chrome.py`) if bot-blocked.
- Always cite source and date inline: `[$X.XX — Amazon, 2026-06-02]`
- If no pricing source is reachable, state that explicitly. Do NOT substitute a guess or a range
"from memory."
- Applies in all contexts: Discord bot, main session, any Claude session in this repo.
## Scope
Applies to ALL estimate types:
- Computer hardware (drives, RAM, CPUs, etc.)
- Replacement parts and peripherals
- Software licensing and subscriptions
- Third-party service quotes
- Repair labor estimates (when citing market rates)
## Why
Hardware prices fluctuate significantly. A "budget" vs "mid-range" vs "quality" drive can
vary by 2-3x depending on current market. Presenting stale or fabricated numbers to clients
damages trust and can result in inaccurate quotes.

View File

@@ -0,0 +1,117 @@
# Session Log — 2026-06-02 — Glaz-Tech Industries
## User
- **User:** Mike Swanson (mike)
- **Machine:** GURU-BEAST-ROG
- **Role:** admin
---
## Session Summary
Mike requested a transport rule in the Glaztech Exchange Online tenant to allow messages from MailProtector as `noreply@azcomputerguru.com` through spam filtering. These are MailProtector quarantine digest notifications sent to Glaztech users on behalf of ACG's no-reply address.
Before creating the rule, a message trace was pulled (via `Get-MessageTraceV2`) for `noreply@azcomputerguru.com` over the past 10 days to verify that messages were in fact being filtered by Microsoft. The trace confirmed the issue: the vast majority of digest messages delivered successfully, but some recipients were hitting `FilteredAsSpam` status (e.g., `tshaw@glaztech.com` on 2026-06-02 at 3:07 PM). The `gtimail@glaztech.com` address showed `Failed` status on every daily send — this is caused by the existing "GTIMail No-Reply - Reject Inbound" transport rule (Priority 1, `SentToPredicate``RejectMessageAction`) and is a separate, pre-existing issue noted for follow-up.
Authentication to Exchange Online used the ComputerGuru Exchange Operator multi-tenant app (`b43e7342`) with certificate-based credentials from the vault. The token was acquired via `get-token.sh` for the `exchange-op` tier against the Glaztech tenant (`82931e3c-de7a-4f74-87f7-fe714be1f160`) and passed to `Connect-ExchangeOnline -AccessToken` with EXO PowerShell V3 (3.9.2).
A new transport rule was created: **"SCL Bypass - noreply@azcomputerguru.com (MailProtector digests)"** at Priority 4, condition `From: noreply@azcomputerguru.com`, action `SetSCL -1`. This bypasses all spam and junk folder filtering for these digests. The rule was verified active immediately after creation.
---
## Key Decisions
- **SCL = -1 rather than domain-level bypass:** The sender address `noreply@azcomputerguru.com` is specific enough that setting SCL=-1 on it carries minimal risk. A domain-level bypass (`azcomputerguru.com`) was considered but rejected — too broad, would cover all ACG-origin mail.
- **Priority 4:** Placed below the existing SCL bypass rules (Priority 23) since no conflict exists; priority ordering doesn't matter for non-overlapping senders. Placed above any catch-all rules that might exist in the future.
- **Did not restrict by connector:** The "Inbound Spam Filter" connector has no SenderIPAddresses restriction (per prior decision — avoids blocking calendar invites from external M365 tenants). Adding a connector-based condition to the rule was avoided for the same reason.
- **gtimail@glaztech.com not addressed:** The daily `Failed` delivery to `gtimail@glaztech.com` is caused by the pre-existing "GTIMail No-Reply - Reject Inbound" rule. Mike did not request any change to that rule; flagged for separate review.
---
## Problems Encountered
- **`Get-MessageTrace` deprecated:** Initial call to `Get-MessageTrace` returned a deprecation warning and failed. Switched to `Get-MessageTraceV2`. Note: `Get-MessageTraceV2` does not accept `-PageSize` — that parameter does not exist on the V2 cmdlet.
- **`New-TransportRule -SenderAddresses` not valid:** First attempt used `-SenderAddresses` which is not a valid parameter. Correct parameter is `-From` for explicit sender address matching.
- **Cert not in Windows cert store:** Exchange Operator cert (`A615823DE1CAF15229027DEC075AFE32B900D82C`) is not installed in LocalMachine\My or CurrentUser\My on BEAST. Used `get-token.sh` cert-based JWT flow instead, passing the resulting bearer token to `Connect-ExchangeOnline -AccessToken`.
---
## Configuration Changes
- **Exchange Online transport rule created** in `glaztechindustries.onmicrosoft.com`:
- Name: `SCL Bypass - noreply@azcomputerguru.com (MailProtector digests)`
- Condition: `From = noreply@azcomputerguru.com`
- Action: `SetSCL -1`
- Priority: 4
- State: Enabled
- Comments: "Bypass spam filtering for MailProtector quarantine digest emails sent as noreply@azcomputerguru.com. Created 2026-06-02 by ACG."
---
## Credentials & Secrets
- **Vault path used:** `msp-tools/computerguru-exchange-operator.sops.yaml`
- App: ComputerGuru - Exchange Operator
- Client ID: `b43e7342-5b4b-492f-890f-bb5a4f7f40e9`
- Cert thumbprint: `A615823DE1CAF15229027DEC075AFE32B900D82C`
- Token acquired via: `bash .claude/skills/remediation-tool/scripts/get-token.sh <tenant-id> exchange-op`
---
## Infrastructure & Servers
- **Glaztech tenant:** `glaztechindustries.onmicrosoft.com`
- **Tenant ID:** `82931e3c-de7a-4f74-87f7-fe714be1f160`
- **Inbound mail filter:** MailProtector — `glaztech-com.inbound.emailservice.io`
- **Inbound connector:** "Inbound Spam Filter" — Partner type, RequireTls=True, no IP restriction (intentional — preserves calendar invite delivery)
- **EXO PowerShell module:** ExchangeOnlineManagement 3.9.2
---
## Commands & Outputs
```powershell
# Connect to Glaztech EXO with app-only token
$token = bash .claude/skills/remediation-tool/scripts/get-token.sh 82931e3c-de7a-4f74-87f7-fe714be1f160 exchange-op
Connect-ExchangeOnline -AccessToken $token -Organization 'glaztechindustries.onmicrosoft.com' -ShowBanner:$false
# Message trace (last 10 days) — confirmed FilteredAsSpam occurrences
Get-MessageTraceV2 -SenderAddress 'noreply@azcomputerguru.com' -StartDate (Get-Date).AddDays(-10) -EndDate (Get-Date)
# Key finding: tshaw@glaztech.com → FilteredAsSpam (2026-06-02 3:07 PM)
# Key finding: gtimail@glaztech.com → Failed daily (pre-existing rule, separate issue)
# Create rule
New-TransportRule `
-Name 'SCL Bypass - noreply@azcomputerguru.com (MailProtector digests)' `
-From 'noreply@azcomputerguru.com' `
-SetSCL -1 `
-Priority 4 `
-Comments 'Bypass spam filtering for MailProtector quarantine digest emails sent as noreply@azcomputerguru.com. Created 2026-06-02 by ACG.' `
-Enabled $true
```
**Final transport rule list (Glaztech):**
```
Priority 0 Pensky Allow Enabled
Priority 1 GTIMail No-Reply - Reject Inbound Enabled
Priority 2 SCL Bypass - hartsglass + olemons (SHVSALES) Enabled
Priority 3 SCL Bypass - aaaglassinc.com (SHVSALES) Enabled
Priority 4 SCL Bypass - noreply@azcomputerguru.com (MailProtector digests) Enabled
```
---
## Pending / Incomplete Tasks
- **gtimail@glaztech.com failing daily:** The "GTIMail No-Reply - Reject Inbound" rule (Priority 1) rejects all inbound mail to `gtimail@glaztech.com`. This causes the daily MailProtector digest to fail for that address. Confirm with Steve Eastman whether `gtimail@glaztech.com` should receive digests (i.e., whether the reject rule should have an exception or be modified).
- **Exchange Operator cert not in BEAST cert store:** If cert-based PowerShell connections are needed without `get-token.sh` (e.g., for interactive EXO sessions), the cert will need to be imported to the machine store. Not urgent — token flow works fine for bot-driven operations.
---
## Reference Information
- **Syncro customer ID:** 143932
- **EXO rule created:** `SCL Bypass - noreply@azcomputerguru.com (MailProtector digests)` — Priority 4
- **EXO PowerShell V2 deprecation note:** `Get-MessageTrace` deprecated Sept 1 2025; use `Get-MessageTraceV2` (no `-PageSize` parameter)
- **Vault:** `msp-tools/computerguru-exchange-operator.sops.yaml`
- **Token cache:** `/tmp/remediation-tool/82931e3c-de7a-4f74-87f7-fe714be1f160/exchange-op.jwt`

View File

@@ -73,6 +73,23 @@ drive the human's interactive session.
---
## Pricing — Always Verify, Never Guess
**MANDATORY:** Before presenting any cost to Mike, Howard, or a client, verify current pricing
via live web lookup. Never estimate or recall costs from training data — hardware prices,
software licensing, and labor rates change constantly.
Rules:
- Any dollar amount for hardware, parts, software, or services requires a real-time lookup
before being stated.
- Use WebFetch / WebSearch first. Fall back to headless Chrome if bot-blocked.
- Cite the source and date: `[$X.XX — Amazon, 2026-06-02]`
- If you cannot reach a pricing source, say so explicitly — do NOT substitute a guess.
- Applies to all estimate types: parts, repair quotes, hardware refreshes, software licensing,
labor, and third-party services.
---
## Task Loop
For every request, work this loop:
@@ -86,13 +103,41 @@ For every request, work this loop:
4. **Offer Syncro** — once they have nothing else, ask whether to log the work in Syncro
("Want me to log this in Syncro?"). If yes, invoke `/syncro` to create or update the ticket.
5. **Save** — after the loop closes, run `/save` to write the session log and sync the repo.
6. **Kill the thread** — after `/save` completes successfully, delete the thread:
```bash
bash C:/Users/guru/ClaudeTools/projects/discord-bot/scripts/delete-thread.sh <Thread ID>
```
The Thread ID is in every `[DISCORD_CONTEXT]` block as `Thread ID: <id>`. Do not delete
if `/save` failed or errored. Do not post a closing message — the deletion is immediate.
---
## Thread Lifecycle — Auto-Delete on Completion
Every `[DISCORD_CONTEXT]` block now includes `Thread ID: <id>` (injected by the bot after
the thread is resolved or created). This ID is what you pass to the delete script.
**When to delete:** Only after step 6 of the Task Loop — `/save` succeeded, session log
committed and pushed. The thread is the conversation record; don't kill it before the log lands.
**When NOT to delete:**
- `/save` failed or sync errored
- The user said "yes" to continuing (open follow-up items remain)
- The thread is an ongoing informational channel, not a single-task session
**Script:**
```bash
bash C:/Users/guru/ClaudeTools/projects/discord-bot/scripts/delete-thread.sh <Thread ID>
```
Source: `projects/discord-bot/scripts/delete-thread.sh` — reads bot token from `.env`, calls
`DELETE /channels/{id}` on the Discord API. Exits 0 on HTTP 200/204, 1 on error.
---
## Who Is Asking: Discord User Identity
Every message is prefixed with a `[DISCORD_CONTEXT]` block containing the sender's Discord
username, display name, and user ID. Always read this block to determine who is asking.
username, display name, user ID, and Thread ID. Always read this block to determine who is asking.
### Known Team Members — Full Access

View File

@@ -41,7 +41,18 @@ class MessageHandler:
await message.reply("Hey! How can I help?")
return
# Resolve or create the thread first so we can include its ID in context.
if isinstance(message.channel, discord.Thread):
thread = message.channel
else:
name = self._thread_name(user_text) if user_text else "Attachment"
thread = await message.create_thread(
name=name,
auto_archive_duration=1440,
)
# Build caller-identity header so the agent always knows who is asking.
# Thread ID is included so the agent can delete the thread on completion.
author = message.author
display = getattr(author, "display_name", author.name)
guild_name = message.guild.name if message.guild else "DM"
@@ -51,20 +62,11 @@ class MessageHandler:
f"User: @{author.name}"
+ (f" (display: {display})" if display != author.name else "")
+ f" | ID: {author.id}\n"
f"Channel: #{channel_name} | Guild: {guild_name}\n"
f"Channel: #{channel_name} | Thread ID: {thread.id} | Guild: {guild_name}\n"
"[/DISCORD_CONTEXT]\n\n"
)
content = (discord_ctx + user_text).strip()
if isinstance(message.channel, discord.Thread):
thread = message.channel
else:
name = self._thread_name(user_text) if user_text else "Attachment"
thread = await message.create_thread(
name=name,
auto_archive_duration=1440,
)
attachment_paths = await self._download_attachments(message, thread.id)
if attachment_paths:
lines = "\n".join(f"- {p}" for p in attachment_paths)

View File

@@ -0,0 +1,56 @@
#!/usr/bin/env bash
# delete-thread.sh <thread_id>
#
# Deletes a Discord thread (channel) via the Discord REST API.
# Reads the bot token from projects/discord-bot/.env (DISCORD_TOKEN=...).
#
# Exit codes:
# 0 — deleted (HTTP 200 or 204)
# 1 — bad args, token not found, or API error
set -euo pipefail
THREAD_ID="${1:-}"
if [ -z "$THREAD_ID" ]; then
echo "[ERROR] Usage: delete-thread.sh <thread_id>" >&2
exit 1
fi
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ENV_FILE="$SCRIPT_DIR/../.env"
if [ ! -f "$ENV_FILE" ]; then
echo "[ERROR] .env not found at $ENV_FILE" >&2
exit 1
fi
# Extract token — handles quoted and unquoted values, ignores inline comments
DISCORD_TOKEN=$(grep '^DISCORD_TOKEN=' "$ENV_FILE" \
| head -1 \
| sed 's/^DISCORD_TOKEN=//' \
| sed "s/[\"']//g" \
| sed 's/#.*//' \
| tr -d '[:space:]')
if [ -z "$DISCORD_TOKEN" ]; then
echo "[ERROR] DISCORD_TOKEN not found or empty in $ENV_FILE" >&2
exit 1
fi
RESP=$(curl -s -o /tmp/discord_delete_resp.txt -w "%{http_code}" \
-X DELETE \
"https://discord.com/api/v10/channels/${THREAD_ID}" \
-H "Authorization: Bot ${DISCORD_TOKEN}" \
-H "Content-Type: application/json")
HTTP_CODE="$RESP"
BODY=$(cat /tmp/discord_delete_resp.txt 2>/dev/null || echo "")
rm -f /tmp/discord_delete_resp.txt
if [ "$HTTP_CODE" = "200" ] || [ "$HTTP_CODE" = "204" ]; then
echo "[OK] Thread ${THREAD_ID} deleted (HTTP ${HTTP_CODE})"
exit 0
else
echo "[ERROR] Delete failed: HTTP ${HTTP_CODE}${BODY}" >&2
exit 1
fi

View File

@@ -2,11 +2,13 @@
type: client
name: glaztech
display_name: Glaz-Tech Industries
last_compiled: 2026-05-24
last_compiled: 2026-06-02
compiled_by: DESKTOP-0O8A1RL/claude-main
sources:
- clients/glaztech/session-logs/2026-04-20-session.md
- clients/glaztech/session-logs/2026-04-21-session.md
- clients/glaztech/session-logs/2026-05-28-session.md
- clients/glaztech/session-logs/2026-06-02-session.md
- clients/glaztech/reports/2026-04-17-phishing-incident-report.md
- clients/glaztech/PROJECT_STATE.md
- clients/glaztech/README.md
@@ -43,12 +45,39 @@ No dedicated on-premises server infrastructure documented. Multi-site Windows en
- **Tenant ID:** 82931e3c-de7a-4f74-87f7-fe714be1f160
- **Primary domain:** glaztech.com
- **Inbound mail filter:** MailProtector — `glaztech-com.inbound.emailservice.io` (MX 5, sole MX as of 2026-04-17)
- **MailProtector IPs (EFSkipIPs on inbound connector):** 162.248.93.233, 162.248.93.81, 65.113.52.82
- **DMARC:** p=reject; sp=reject (hardened 2026-04-17, was p=none)
- **DKIM:** CNAME records exist for selector1/selector2 — active status unverified [WARNING: confirm DKIM is active in M365]
- **MFA status:** [WARNING] DISABLED as of 2026-04-21. Security Defaults off. No Conditional Access (requires Entra P1, not licensed). ~160 users with password-only sign-in. MFA rollout is open work item — do not enable Security Defaults until service account audit is complete (see Active Work).
- **Licensing:** Basic M365 (no Entra P1 / Business Premium). Per-user MFA or Security Defaults are the available free options.
- **Mailbox forwarding (internal, low risk):** Payroll@glaztech.com → carmen@glaztech.com; TUCCSR@glaztech.com → bryce@glaztech.com
- **OAuth consent grants:** 38 grants — not audited as of last session
- **EXO PowerShell:** ExchangeOnlineManagement 3.9.2. `Get-MessageTrace` deprecated Sept 2025 — use `Get-MessageTraceV2` (no `-PageSize` parameter).
### Exchange Online Transport Rules
Full transport rule list as of 2026-06-02:
| Priority | Name | Condition | Action | State |
|---|---|---|---|---|
| 0 | Pensky Allow | [unknown] | [unknown] | Enabled |
| 1 | GTIMail No-Reply - Reject Inbound | SentTo: gtimail@glaztech.com | RejectMessageAction | Enabled |
| 2 | SCL Bypass - hartsglass + olemons (SHVSALES) | From: hartsglass@centurytel.net, olemons@eastexglass.com, SSales@arkglass.com, bossier@glassservices.com | SetSCL -1 | Enabled |
| 3 | SCL Bypass - aaaglassinc.com (SHVSALES) | SenderDomainIs: aaaglassinc.com | SetSCL -1 | Enabled |
| 4 | SCL Bypass - noreply@azcomputerguru.com (MailProtector digests) | From: noreply@azcomputerguru.com | SetSCL -1 | Enabled |
Rule GUIDs: Priority 2 = 482c714a-8780-4c62-ae0a-0b6da9ca9d52; Priority 3 = 7e0c01a8-ec22-43fe-b600-796c0f295aa5. GUIDs for Priority 0, 1, 4 not recorded.
Note on Priority 1: The "GTIMail No-Reply - Reject Inbound" rule rejects ALL inbound mail to gtimail@glaztech.com, which causes the daily MailProtector digest for that address to fail. This is a pre-existing rule — review with Steve is pending (see Active Work).
### Inbound Connector
- **Name:** "Inbound Spam Filter"
- **Type:** Partner
- **RequireTls:** True
- **EFSkipIPs:** 162.248.93.233, 162.248.93.81, 65.113.52.82 (MailProtector IPs)
- **SCLMinusOne:** null (EOP re-evaluates all mail; do NOT change to true — too broad)
- **SenderIPAddresses restriction:** None (intentional — avoids blocking calendar invites from external M365 tenants)
### Network
@@ -61,11 +90,13 @@ No dedicated on-premises server infrastructure documented. Multi-site Windows en
- **Remediation tool:** ComputerGuru apps consented in tenant (Exchange Operator, Security Investigator, Tenant Admin, Defender Add-on)
- **Exchange Operator App ID:** b43e7342-5b4b-492f-890f-bb5a4f7f40e9
- **Exchange Operator cert thumbprint:** A615823DE1CAF15229027DEC075AFE32B900D82C (not in Windows cert store on BEAST — use `get-token.sh` bearer token flow)
- **Remediation tool app (AI):** fabb3421-8b34-484b-bc17-e46de9703418
- **Exchange Admin role:** Assigned to ACG service principal in Entra
- **Global Admin account:** admin@glaztechindustries.onmicrosoft.com (ACG admin only — external GA from tomakkglass.com removed 2026-04-21)
- **Vault path:** `clients/glaztech/` [no SOPS credential file documented — remediation tool uses MSP-wide app credentials]
- **Exchange Operator vault:** `msp-tools/computerguru-exchange-operator.sops.yaml`
- **Token acquisition:** `bash .claude/skills/remediation-tool/scripts/get-token.sh <tenant-id> exchange-op``Connect-ExchangeOnline -AccessToken $token -Organization 'glaztechindustries.onmicrosoft.com'`
- **DNS access:** `root@172.16.3.10` (IX server)
- **Deploy (endpoints):** ScreenConnect or GuruRMM
@@ -73,9 +104,14 @@ No dedicated on-premises server infrastructure documented. Multi-site Windows en
- **Phishing via direct-to-M365 MX bypass:** Two phishing campaigns in April 2026 succeeded because DNS had a secondary MX record (`glaztech-com.mail.protection.outlook.com` at priority 10) that bypassed MailProtector. Hardened: MX 10 removed, DMARC to p=reject, Enhanced Filtering for Connectors enabled. Do not re-add a secondary MX record.
- **Inbound connector IP restriction:** Do NOT restrict `SenderIPAddresses` on the "Inbound Spam Filter" connector — blocks legitimate calendar invites from external M365 tenants (learned from Dataforth incident). EFSkipIPs are set to MailProtector IPs instead.
- **Do NOT set SCLMinusOne=true on connector:** This would trust MailProtector's verdict for all inbound mail — too broad. Use targeted transport rules for specific senders instead.
- **DMARC-rejecting vendor senders:** With Enhanced Filtering enabled, EOP looks past MailProtector to the original sender's SPF/DKIM/DMARC. Vendors with `p=reject` domains (e.g., centurytel.net, eastexglass.com) get hard 550 5.7.509 NDR rejections. Fix: SCL=-1 transport rule scoped to the specific sender address or domain. Transport rules evaluate before DMARC enforcement in EOP.
- **EXO transport rule name limit:** 64-character maximum. Plan names accordingly.
- **EXO REST API:** Direct `/TransportRule` REST endpoints 404 in this tenant. Use `InvokeCommand` pattern: `POST /adminapi/beta/{tenant}/InvokeCommand` with `{"CmdletInput": {"CmdletName": "New-TransportRule", "Parameters": {...}}}`.
- **Service accounts need audit before MFA rollout:** Shoretel, mitel, Gti-FaxFinder, GTIMail, GTIQUOTE, CAS1944, clerk — all need SMTP/auth method confirmation before Security Defaults can be enabled.
- **PDF preview broken (MOTW):** Windows KB5066791/KB5066835 broke PDF preview on network shares via Mark of the Web. Fix scripts are ready in `clients/glaztech/` — deployment is pending (as of 2026-03-30).
- **clearcutglass.com DMARC history:** Corena Spottsville (clearcutglass.com) emails to seastman and zulema were rejected. Temporary transport rule (SCL=-1) was set and removed on 2026-04-21. SPF ~all weakness noted to Team Logic IT (Jordan Fox, jfox@tlit60302.com); recommend they harden to -all and confirm DKIM.
- **glassservices.com SPF broken:** `bossier@glassservices.com` publishes `v=spf1 -all` — rejected by all mail providers. SCL=-1 rule covers this as a workaround. Steve should notify vendor to fix SPF.
- **Client tone:** ACG has managed GlazTech ~15 years. Steve Eastman is a trusted internal IT partner. Comments and communication should lead with what we know, state findings and actions taken, ask only one targeted question if needed — not open-ended discovery.
- **Unlicensed accounts (pending Steve confirmation):** Chauntelle@glaztech.com, Denouser1@glaztech.com, Gti-FaxFinder@glaztech.com.
@@ -103,6 +139,10 @@ Waiting on Steve's reply to:
MFA rollout plan: Phase 1 — user communication (install Authenticator); Phase 2 — enable enforcement; Phase 3 — follow-up stragglers; Phase 4 (future/P1) — Conditional Access with trusted IPs for office locations.
### gtimail@glaztech.com Daily Digest Failure (Pending — review with Steve)
The "GTIMail No-Reply - Reject Inbound" transport rule (Priority 1) rejects all inbound mail to `gtimail@glaztech.com`, causing the daily MailProtector digest for that address to fail every day. This is a pre-existing rule and was not modified during the 2026-06-02 session. Confirm with Steve Eastman whether `gtimail@glaztech.com` should receive MailProtector digests — if so, the rule needs an exception or the recipient needs to be removed from the MailProtector digest list.
### Pending follow-ups
- Audit 38 OAuth consent grants (not done as of 2026-04-21)
@@ -110,7 +150,9 @@ MFA rollout plan: Phase 1 — user communication (install Authenticator); Phase
- Monitor DMARC aggregate reports (rua=noreply@glaztech.com — should be a monitored mailbox or reporting service)
- Security awareness training for staff (multiple employees forwarded and replied to obvious phishing in April 2026)
- Review whether any user clicked phishing links (check sign-in logs for suspicious auth attempts post-April 17)
- Confirm test email clean delivery from clearcutglass.com after DMARC fix
- Notify Steve: glassservices.com vendor needs to fix their SPF record (`v=spf1 -all`)
- Harts Glass original rejected emails need to be resent by sender — our SCL bypass is live but NDR'd messages do not auto-retry
- Consider creating retroactive Syncro ticket for 2026-05-28 SHVSALES email delivery work
## History Highlights
@@ -119,6 +161,8 @@ MFA rollout plan: Phase 1 — user communication (install Authenticator); Phase
- **2026-04-17** — Two phishing campaigns bypassed MailProtector via direct-to-M365 MX bypass. 32 messages purged across 8 users. Hardened: MX 10 removed, DMARC p=reject, Enhanced Filtering Connectors enabled. Remediation tool onboarded (admin consent, Exchange Admin role). Forensic evidence preserved in `clients/glaztech/reports/`.
- **2026-04-20** — Exchange transport rule created to allow clearcutglass.com mail (DMARC bypass, SCL=-1) while Team Logic IT fixed their DNS. Ticket #32176 created.
- **2026-04-21** — clearcutglass.com DNS fixed by Team Logic IT (Jordan Fox). Transport rule removed. External Global Admin (glaztechadmin from tomakkglass.com / Team Logic IT) removed from tenant. M365 security review surfaced: no MFA, 38 OAuth grants, unlicensed accounts, service account audit needed. Ticket #32186 opened for MFA implementation. Feedback: use expert-partner tone with Steve, not open-ended discovery questions.
- **2026-05-28** — SHVSALES@glaztech.com vendor email delivery failure. Root cause: vendors (centurytel.net, eastexglass.com) publish DMARC p=reject; Enhanced Filtering re-evaluates past MailProtector relay, producing 550 5.7.509 NDR. Fix: two SCL=-1 transport rules created (Priority 2: specific addresses for hartsglass, olemons, SSales, bossier; Priority 3: aaaglassinc.com domain). glassservices.com SPF broken (`-all`) — workaround only, vendor must fix.
- **2026-06-02** — MailProtector quarantine digest messages from `noreply@azcomputerguru.com` confirmed hitting `FilteredAsSpam` for some recipients (e.g., tshaw@glaztech.com). Transport rule created: "SCL Bypass - noreply@azcomputerguru.com (MailProtector digests)" at Priority 4 (From=noreply@azcomputerguru.com, SetSCL=-1). Message trace via `Get-MessageTraceV2` also revealed `gtimail@glaztech.com` failing daily due to pre-existing Priority 1 reject rule — flagged for Steve review.
## Backlinks

View File

@@ -25,7 +25,7 @@ Run `/wiki-lint` to check for stale entries and broken backlinks.
| [ACG Internal Infrastructure](clients/internal-infrastructure.md) | ACG's own hosting infra — Neptune Exchange (cert expires 2026-05-31, DkimSigner disabled), IX server, Cloudflare tunnel workaround, ACG M365 tenant gaps | 2026-05-24 |
| [BirthBiologic](clients/birth-biologic.md) | Bio/healthcare; BB-SERVER (WS2016) GuruRMM enrolled; Datto→SharePoint migration incomplete; M365 apps partially consented | 2026-05-24 |
| [CryoWeave](clients/cryoweave.md) | Custom cryogenic cable assemblies; cPanel on IX; website redesign + SEO project in progress; Syncro ID not documented | 2026-05-24 |
| [Glaz-Tech Industries](clients/glaztech.md) | ~200 users, 9 locations; M365; two phishing campaigns bypassed MailProtector via secondary MX (removed); no MFA enforcement yet | 2026-05-24 |
| [Glaz-Tech Industries](clients/glaztech.md) | ~200 users, 9 locations; M365; two phishing campaigns bypassed MailProtector via secondary MX (removed); no MFA enforcement yet; SCL bypass rules for vendor DMARC failures + MailProtector digests | 2026-06-02 |
| [Grabb & Durando Law Office](clients/grabb-durando.md) | Personal injury law firm; GND-SERVER GuruRMM enrolled; AI demand review app scoped ($4K$7K); website migration pending; plaintext DB password in README needs vaulting | 2026-05-24 |
| [Pavon](clients/pavon.md) | Former/archive client; GeoVision NVR surveillance; OwnCloud at 172.16.3.22 backed by Uranus; cron stacking fixed; Nextcloud migration deferred 36 months | 2026-05-24 |
| [Rednour Law Offices](clients/rednour.md) | Law firm; M365 rednourlaw.com (tenant 4a4ca18a) fully onboarded 2026-05-31; all 5 ComputerGuru SPs consented; no MDE license; 3 workstations GuruRMM enrolled (FRONTDESKRECEPT/LEGALASST/REDNOURCARRIEVI); Carla Skinner renamed from Emma; prior MSP agents (ScreenConnect/Splashtop/Datto) still present; shared-drive access for Nick Pafford deferred | 2026-06-02 |