fix(devices): flag stale device agents as non-compliant + CSV export#2612
Merged
fix(devices): flag stale device agents as non-compliant + CSV export#2612
Conversation
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Contributor
Author
|
@cubic-dev-ai review this |
Contributor
@Marfuen I have started the AI code review. It will take a few minutes to complete. |
Contributor
There was a problem hiding this comment.
3 issues found across 17 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="apps/app/src/app/(app)/[orgId]/people/devices/lib/devices-csv.ts">
<violation number="1" location="apps/app/src/app/(app)/[orgId]/people/devices/lib/devices-csv.ts:19">
P2: CSV injection (formula injection) risk: cells starting with `=`, `+`, `-`, or `@` are not sanitized, so a malicious device name like `=CMD(...)` could execute when the file is opened in a spreadsheet. Prefix dangerous leading characters with a single quote or tab to neutralize them.</violation>
</file>
<file name="apps/app/src/trigger/tasks/device/flag-stale-devices.ts">
<violation number="1" location="apps/app/src/trigger/tasks/device/flag-stale-devices.ts:10">
P2: `maxDuration` in trigger.dev is specified in seconds, not milliseconds. `1000 * 60 * 5` = 300,000 seconds (~3.5 days), not 5 minutes. The correct value is `60 * 5` (300 seconds). Other tasks in this repo use the same pattern, so this likely doesn't cause real issues (trigger.dev probably caps at the plan limit), but it's worth noting for correctness.</violation>
</file>
<file name="packages/utils/src/devices.ts">
<violation number="1" location="packages/utils/src/devices.ts:54">
P1: An invalid date string (empty or malformed) causes `daysSinceCheckIn` to return `NaN`, which makes `isDeviceStale` return `false` because `NaN >= 7` is `false` in JavaScript. This silently treats devices with corrupt `lastCheckIn` values as non-stale, undermining the security intent of this feature. Add a `NaN` guard to treat unparseable dates as stale.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review, or fix all with cubic.
- packages/utils: guard daysSinceCheckIn against NaN so corrupt lastCheckIn strings are treated as stale (P1). - devices-csv: neutralize CSV formula injection (leading =, +, -, @, tab, CR) by prefixing with apostrophe per OWASP (P2). - flag-stale-devices: maxDuration is in seconds, not ms (P2).
…trycompai/comp into mariano/stale-device-compliance
Contributor
Author
|
@cubic-dev-ai review this |
Contributor
@Marfuen I have started the AI code review. It will take a few minutes to complete. |
claudfuen
pushed a commit
that referenced
this pull request
Apr 20, 2026
# [3.27.0](v3.26.1...v3.27.0) (2026-04-20) ### Bug Fixes * **devices:** flag stale device agents as non-compliant + CSV export ([#2612](#2612)) ([0d59e8f](0d59e8f)) * **integration-platform:** preserve VCS url fragments in python matcher ([f820738](f820738)) * **integration-platform:** use toml-aware comment stripping for pyproject.toml ([2cf8979](2cf8979)) * **integrations-catalog:** add global request pacing to prevent 429s ([0dfb793](0dfb793)) ### Features * add compliance timeline to overview (feature flagged) ([26c04d8](26c04d8)) * **integration-platform:** expand validation library detection for sanitized inputs check ([964cb1b](964cb1b)) * **integrations-catalog:** add public catalog ([ea297de](ea297de)) ### Reverts * Revert "chore(app): remove the duplicated prisma/ setup" ([#2621](#2621)) ([a1889a1](a1889a1))
Contributor
|
🎉 This PR is included in version 3.27.0 🎉 The release is available on GitHub release Your semantic-release bot 📦🚀 |
4 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
stale) in the API and the UI, and a daily trigger.dev cron flipsisCompliant = falsein the DB so direct queries stay honest.What changed
packages/utils/src/devices.ts— pure helpers:STALE_DEVICE_THRESHOLD_DAYS,daysSinceCheckIn,isDeviceStale,getDeviceComplianceStatus.apps/app/src/app/api/people/agent-devices/route.ts+ NestJSDevicesService.mapAgentDeviceToDto— both derivecomplianceStatuson read.apps/app/src/trigger/tasks/device/flag-stale-devices.ts— daily cron at0 6 * * *UTC.DeviceAgentDevicesList.tsx— three-state compliant badge (Yes / No / Stale (Nd)); stale rows render check badges as neutral em-dashes; new Export CSV button.DeviceComplianceChart.tsx— now counts stale devices toward Non-Compliant (matches the table).Test plan
/<orgId>/people→ Devices tab.lastCheckInolder than 7 days (tweak via Prisma Studio if needed), confirm the row shows a muted "Stale (Nd)" badge and neutral em-dash check badges.devices-<orgId>-<YYYY-MM-DD>.csv, opens cleanly in Excel, non-ASCII device names render correctly.flag-stale-devicestrigger.dev schedule appears in the Trigger.dev dashboard and runs successfully on its first invocation.Notes
'non-compliant'vocabulary on/v1/devices.statusis preserved for external API consumers; internal code uses underscore form.DeviceComplianceChartstays binary (stale counts toward Non-Compliant) rather than adding a third slice.🤖 Generated with Claude Code
Summary by cubic
Flags device agents that haven’t checked in for 7+ days as a new “stale” state across API and UI, and adds a hardened CSV export for the devices list to support update campaigns. Stale devices are treated as non‑compliant in charts and the external API now returns
'stale'.New Features
@trycompai/utils(compliant,non_compliant,stale) with helpers;/api/people/agent-devicesreturnscomplianceStatusanddaysSinceLastCheckIn; v1 devices DTO exposes'compliant' | 'non-compliant' | 'stale'.devices-<org|slug>-<YYYY-MM-DD>.csv; escapes quotes/newlines and neutralizes CSV injection by prefixing leading= + - @(tab/CR) with'.Bug Fixes
@trigger.dev/sdktask flips them toisCompliant = false.daysSinceCheckInguards invalidlastCheckInstrings (treated as stale).'non-compliant'while internal code uses underscores.Written for commit dba59ff. Summary will update on new commits.