Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,17 @@ SOCKET_AGENT_ACK_MAX_RETRIES=1
# Guardrails before packing sql.bulkInsert into PayloadFrame. Split larger imports into batches.
AGENT_SQL_BULK_INSERT_MAX_ROWS=50000
AGENT_SQL_BULK_INSERT_MAX_JSON_BYTES=10485760
# Agent -> hub auto-update diagnostics notification ingestion.
# Disabled by default for safe rollout. When enabled, accepts only
# `agent.autoUpdate.diagnostics.push` notifications on /agents `rpc:request`.
AGENT_AUTO_UPDATE_DIAGNOSTICS_ENABLED=false
AGENT_AUTO_UPDATE_DIAGNOSTICS_RATE_LIMIT_WINDOW_MS=60000
AGENT_AUTO_UPDATE_DIAGNOSTICS_RATE_LIMIT_MAX=1
AGENT_AUTO_UPDATE_DIAGNOSTICS_RETENTION_DAYS=90
AGENT_AUTO_UPDATE_DIAGNOSTICS_RETENTION_INTERVAL_MINUTES=1440
AGENT_AUTO_UPDATE_DIAGNOSTICS_PRUNE_BATCH_SIZE=5000
AGENT_AUTO_UPDATE_DIAGNOSTICS_MAX_PAYLOAD_BYTES=16384
AGENT_AUTO_UPDATE_DIAGNOSTICS_MAX_MESSAGE_BYTES=65536
# REST bridge per-agent overload controls (short queue + fail-fast)
# REST per-agent parallelism and queue (higher inflight = more concurrent commands per agent)
SOCKET_REST_AGENT_MAX_INFLIGHT=32
Expand Down
4 changes: 0 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,5 @@ jobs:
- name: Test
run: npm run test

# E2E roda só com E2E_TESTS_ENABLED=true no ambiente (ex. secret + .env no job); sem isso exit 0.
- name: E2E (optional gate)
run: npm run test:e2e

- name: Build
run: npm run build
76 changes: 76 additions & 0 deletions .github/workflows/e2e.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
name: E2E

on:
workflow_dispatch:
schedule:
- cron: "0 6 * * *"

jobs:
communication-e2e:
runs-on: ubuntu-latest
services:
postgres:
image: postgres:16-alpine
env:
POSTGRES_USER: ci
POSTGRES_PASSWORD: ci
POSTGRES_DB: plug_e2e
ports:
- 5432:5432
options: >-
--health-cmd "pg_isready -U ci -d plug_e2e"
--health-interval 5s
--health-timeout 3s
--health-retries 20
redis:
image: redis:7-alpine
ports:
- 6379:6379
options: >-
--health-cmd "redis-cli ping"
--health-interval 5s
--health-timeout 3s
--health-retries 20
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
NODE_ENV: test
DATABASE_URL: postgresql://ci:ci@localhost:5432/plug_e2e
CONTAINER_PERSISTENCE_MODE: prisma
CONTAINER_EMAIL_SENDER_MODE: noop
E2E_TESTS_ENABLED: "true"
AGENT_AUTO_UPDATE_DIAGNOSTICS_ENABLED: "true"
INTEGRATION_REDIS_TESTS_ENABLED: "true"
SOCKET_IO_REDIS_ADAPTER_URL: redis://127.0.0.1:6379
REST_SOCKET_EVENT_IDEMPOTENCY_REDIS_URL: redis://127.0.0.1:6379
SOCKET_RATE_LIMIT_REDIS_URL: redis://127.0.0.1:6379
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 22
cache: npm

- name: Install dependencies
run: npm ci

- name: Migrate E2E database
run: npm run db:migrate:deploy

- name: Run E2E suite
run: npm run test:e2e

- name: Upload E2E artifacts
if: always()
uses: actions/upload-artifact@v4
with:
name: e2e-artifacts
if-no-files-found: ignore
path: |
test-results
coverage
logs
*.log
npm-debug.log*
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
-- Dedicated fleet observability table for agent.autoUpdate.diagnostics.push.
CREATE TABLE "agent_auto_update_diagnostics" (
"id" TEXT NOT NULL,
"agent_id" VARCHAR(36) NOT NULL,
"app_version" VARCHAR(64) NOT NULL,
"check_id" VARCHAR(128),
"checked_at" TIMESTAMP(3) NOT NULL,
"source" VARCHAR(32) NOT NULL,
"completion_source" VARCHAR(64),
"remote_version" VARCHAR(64),
"update_available" BOOLEAN,
"channel" VARCHAR(32),
"rollout_bucket" INTEGER,
"feed_signature_status" VARCHAR(64),
"feed_signature_required" BOOLEAN,
"helper_signature_status" VARCHAR(64),
"probe_duration_ms" INTEGER,
"download_duration_ms" INTEGER,
"automatic_failure_count" INTEGER,
"error_message" VARCHAR(1024),
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,

CONSTRAINT "agent_auto_update_diagnostics_pkey" PRIMARY KEY ("id")
);

ALTER TABLE "agent_auto_update_diagnostics"
ADD CONSTRAINT "agent_auto_update_diagnostics_agent_id_fkey"
FOREIGN KEY ("agent_id") REFERENCES "agents"("agent_id")
ON DELETE CASCADE ON UPDATE CASCADE;

CREATE INDEX "agent_auto_update_diagnostics_agent_id_idx"
ON "agent_auto_update_diagnostics"("agent_id");

CREATE INDEX "agent_auto_update_diagnostics_checked_at_idx"
ON "agent_auto_update_diagnostics"("checked_at");

CREATE INDEX "agent_auto_update_diagnostics_app_version_idx"
ON "agent_auto_update_diagnostics"("app_version");

CREATE INDEX "agent_auto_update_diagnostics_completion_source_idx"
ON "agent_auto_update_diagnostics"("completion_source");

CREATE INDEX "agent_auto_update_diagnostics_source_idx"
ON "agent_auto_update_diagnostics"("source");

CREATE INDEX "agent_auto_update_diagnostics_agent_id_checked_at_idx"
ON "agent_auto_update_diagnostics"("agent_id", "checked_at");

32 changes: 32 additions & 0 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -196,13 +196,45 @@ model Agent {
clientAccessRequests ClientAgentAccessRequest[]
profileRevisions AgentProfileRevision[]
profileWriteIdempotencies AgentProfileWriteIdempotency[]
autoUpdateDiagnostics AgentAutoUpdateDiagnostics[]

@@index([lastLoginUserId])
@@index([status])

@@map("agents")
}

model AgentAutoUpdateDiagnostics {
id String @id @default(uuid())
agentId String @map("agent_id") @db.VarChar(36)
agent Agent @relation(fields: [agentId], references: [agentId], onDelete: Cascade, onUpdate: Cascade)
appVersion String @map("app_version") @db.VarChar(64)
checkId String? @map("check_id") @db.VarChar(128)
checkedAt DateTime @map("checked_at")
source String @db.VarChar(32)
completionSource String? @map("completion_source") @db.VarChar(64)
remoteVersion String? @map("remote_version") @db.VarChar(64)
updateAvailable Boolean? @map("update_available")
channel String? @db.VarChar(32)
rolloutBucket Int? @map("rollout_bucket")
feedSignatureStatus String? @map("feed_signature_status") @db.VarChar(64)
feedSignatureRequired Boolean? @map("feed_signature_required")
helperSignatureStatus String? @map("helper_signature_status") @db.VarChar(64)
probeDurationMs Int? @map("probe_duration_ms")
downloadDurationMs Int? @map("download_duration_ms")
automaticFailureCount Int? @map("automatic_failure_count")
errorMessage String? @map("error_message") @db.VarChar(1024)
createdAt DateTime @default(now()) @map("created_at")

@@index([agentId])
@@index([checkedAt])
@@index([appVersion])
@@index([completionSource])
@@index([source])
@@index([agentId, checkedAt])
@@map("agent_auto_update_diagnostics")
}

model AgentProfileRevision {
id String @id @default(uuid())
agentId String @map("agent_id") @db.VarChar(36)
Expand Down
Loading
Loading