Repository navigation
v0.1.23-alpha
Pre-release
Pre-release
·
114 commits
to main
since this release
İmzalı sürüm (ed25519).
manifest.jsonvemanifest.json.sigrelease'e dahildir; açık anahtar depodakeys/pops_release_ed25519.pub.pem. Doğrulama için bkz.keys/README.md. Ajan içinPOps-Agent-*-win-x64.msiönerilir (sessiz kurulum ve özellikleri:Installer/README.md); zip eski elle kurulum yoludur. Ajan paketleri Windows'ta SmartScreen uyarısı verebilir (Authenticode imzası henüz yok). MSI kendi .NET 10 çalışma zamanını getirir; uç noktada önceden bir şey kurmak gerekmez. Pardus/Debian içinpops-agent_*_all.deb(Debian 12 / Pardus 23 ve sonrası; kurulum:Agent-Linux/README.md).
For operators, in short:
- New in the panel:
- Exam mode per lab: the network is limited to an allow list, with optional app blocking. It lasts at most 8 hours and ends on time even offline.
- File transfer: send a file to PCs, or fetch one from a PC with a reason.
- Power actions with a countdown and a note, and messages to the user with an optional read receipt.
- winget packages in Dağıtım, with a 69-app catalogue.
- Vision v2: several screens, adaptive quality, and clipboard in a session the user accepted.
- Every page in English.
- For organisations:
- Sign-in with Active Directory/LDAP or OpenID Connect.
- Organisational units (district → school): admins and API tokens see only their own schools.
- REST API v1 with tokens, GLPI export and Sistem → Modüller.
- Optionally, several backend workers with Redis.
- Linux agent, first version (Pardus 23+, Debian 12, Ubuntu 24.04; one
.deb):- It reports inventory and installed packages, runs commands, and updates itself from signed releases with rollback.
- It has no screen view, quarantine or tray yet.
- Update your agents (Sistem → Güncellemeler). The new Windows agent is needed for exam mode, file transfer, winget, power actions and messages, and Vision v2. Older agents are recognised: they are skipped, or get the old shutdown command. It also:
- shows each update stage in the panel and resumes downloads (BITS);
- deletes logs after 30 days;
- lets you move the log and data folders.
- Before updating a native server:
- Reinstall
/usr/local/sbin/pops-deploy-backendfrom this release first. Migration0031rewrites large tables, and the new script takes a database dump before it. - Migrations
0024–0032run by themselves; expect a longer first start. - If you edited
Dashboard/assets/pops_config.js, rename its global toPOPS_API. - The lab peer cache for agent updates is off by default.
- Reinstall
Try it without installing: https://demo.pashacore.com.tr (demo / demo, read-only). Known limitations are in the README.
Added
- Agent: lab-local peer cache for updates. The agent announces
peer_cacheinX-Agent-Featuresand follows the server's staged rollout. It downloads an update from thepeersinupdate_agentfirst, then from the server, and checks every source against the signed size and SHA-256. Only whenupdate_agentcarries"peer_cache": true(the server's "Sınıf içinde eşten dağıt" setting, off by default) does it keep the verified package inC:\POpsData\cachefor 2 hours (or until the next update). It then serves it read-only to PCs in its own subnet on TCP 8817:GET/HEAD /pops-cache/<sha256>only, at most 4 transfers, firewall rule group "POps Peer Cache" (LocalSubnet, POpsAgent.exe). Nothing is served or fetched from peers during quarantine or exam mode. Thedownloadedstage names the source (peer <hw_id>,server,cache).capabilitiesreportspeer_cache_enabled;PEER_CACHE_ENABLED=0on the MSI switches it off, and the feature is then not announced. - Several backend workers (optional, D-26). With
REDIS_URLset, the backend can run as several uvicorn workers or on several servers behind a load balancer, without sticky sessions. Off by default: a single-process install behaves as before. Seedocs/ha.md.- Shared through Redis: commands, panel broadcasts, screen frames (only to session holders), Vision messages, the device list, session grants, the online-agent registry, notification limits and login rate limits.
- A dead worker's agents are marked Offline, and one leader runs the periodic jobs. If Redis is down, each worker keeps its own agents and panels running.
tools/agent_simulator.py --url A,Bspreads agents over several backends, and--report-everyprints the split.- Agent: power actions and messages to the user. The agent announces
powerandmessageinX-Agent-Featuresand follows the server'spoweranduser_messageschemas.powershuts the PC down, restarts it, signs the user out or locks it, after a countdown of up to 10 minutes that the tray shows on top with the administrator's note ("Bilgisayar 60 sn içinde yeniden başlatılacak"); the service keeps the time, so it also acts without the tray, and the result is sent just before acting. Lock goes through the tray (LockWorkStation) and falls back to disconnecting the console session; sign-out usesWTSLogoffSession; shutdown and restart useshutdown.exe /f.cancel_taskstops a countdown.user_messageshows a window with a title, a text of up to 1000 characters and an info or warning icon; withrequires_ackthe single result waits for the user's Tamam ([TAMAM] okundu) for up to 30 minutes. Sign-out, lock and messages need a signed-in user (otherwise exit code -6, "[REDDEDİLDİ] oturum açık kullanıcı yok"); a message while a user is signed in but the tray is not running fails with -3. Every field is checked again on the agent and the text is cleaned as on the server (control, text-direction and zero-width characters removed; title and note on one line). Both can be switched off on the PC with the new MSI propertiesPOWER_ENABLED=0/MESSAGE_ENABLED=0(on by default) or by the server withset_capabilities; switching on again needs the MSI. New event log entries 1130 (power action), 1140 and 1141 (message shown and its outcome) hold only metadata, never the message text. - Agent: the
capabilitiesmessage reportsexam_enabled,power_enabledandmessage_enabled(optional fields in the schema), next toterminal_enabled,vision_enabled,files_enabledandserver_ca. - Agent: log and data folders from
appsettings.json.LogDirectoryandDataDirectorymoveC:\POpsLogsandC:\POpsData, for example to a second disk; the defaults are unchanged.- Full local paths only: relative, network (UNC) and device paths, wildcards, alternate data streams, a drive root, the Windows, profiles and install folders,
Program Files/ProgramDatathemselves, and folders whose parent users could replace are refused. A refused value falls back to the default with an error in the log and event 1090; the agent still starts. - The chosen folders get the same permissions as the defaults (no inheritance). The updater and the watchdog get the folders from the service; the MSI uses them on an upgrade or repair. Nothing is moved when the setting changes; see
docs/configuration.md.
- Full local paths only: relative, network (UNC) and device paths, wildcards, alternate data streams, a drive root, the Windows, profiles and install folders,
- Organisational units (district → school). A superadmin builds a tree of units on Ayarlar → Birimler, puts labs into units, and gives users and API tokens a scope.
- A scoped account sees and acts only on its units' devices, sub-units included.
- The server enforces the scope on every endpoint (
Backend/pops/tenancy.py), so it also holds for API tokens. Out-of-scope ids answer404, and organisation-wide settings answer403. - Covered: devices, labs, tasks, deployment and winget, file transfer, exam mode, power actions and messages, Vision, logs, inventory, reports and CSV, licences, tickets, scheduled tasks, notifications, update progress and the panel WebSocket.
- New
/api/org-units;org_scopeon users and tokens; the unit name shows in the sidebar. Nothing changes until units exist. D-25, migration0032.
- Scopes for directory and OIDC accounts. Group mappings can carry a scope (unit ids or
"all"). While units exist, a new directory or OIDC account whose mappings set no scope gets an empty scope, so it is never unscoped by accident. - Panel sign-in with Active Directory / LDAP and OpenID Connect (Microsoft Entra ID, Google, Keycloak …). A superadmin sets it up under Ayarlar → Güvenlik → Kimlik sağlayıcıları.
- Directory users sign in with the usual form; with OIDC the sign-in page shows " ile giriş yap".
- Directory groups (or OIDC group claims) map to İzleyici, Yönetici or Süper admin and to pages, and the mapping is rewritten at every sign-in. Bağlantıyı sına checks the connection and a user's resulting role before saving.
- Users can be created as, or switched to, directory or OIDC accounts. Local accounts keep working when the directory is down.
- Turkish how-to:
docs/tr/active-directory-ile-giris.md. Migration0030; new dependencyldap3(pure Python). Decision D-24.
- Power actions and messages to the user as their own agent messages (
power,user_message), for agents that announceX-Agent-Features: power,message.POST /api/devices/power: shut down, restart, sign out or lock, with a delay of 0–600 s and an optional note of up to 200 characters.POST /api/devices/message: title, text, Bilgi/Uyarı and an optional read receipt.- Both are also under
/api/v1. Migration0028.
- Panel: power and message actions.
- New Oturumu kapat and Kilitle actions.
- Kapat and Yeniden başlat get a Gecikme choice (Hemen / 1 dk / 5 dk / 10 dk) and a "Kullanıcıya not" field.
- New Mesaj gönder dialog with a character counter, Bilgi/Uyarı and "Okundu onayı iste".
- The task drawer explains -6 (nobody signed in) and -8 (the agent does not support it).
- Lab-local peer cache for agent updates, server side. Agents that announce
peer_cache(X-Agent-Features) are updated one PC per lab first: the seed, an online PC with a known LAN address, wired and most recently seen first.- When the seed reports a successful update on its new version, the rest of the lab gets
update_agentwithpeers: 1–3 PCs of the lab that hold the package, athttp://<LAN IP>:<port>/pops-cache/<sha256>. The port is 8817, or the one announced inX-Agent-Peer-Cache. - A seed that does not reach
verifiedor a result within 10 minutes, or fails, is replaced by the next one; with no seed left, the lab is updated without peers. - Agents without the feature, PCs without a lab, labs without a candidate and Linux agents are updated as before. Agents check the signed size and SHA-256 whatever the source.
- When the seed reports a successful update on its new version, the rest of the lab gets
- Sistem → Ajanlar: peer cache switch and progress. "Sınıf içinde eşten dağıt" (off by default: while on, a PC holding a package opens a port to its local subnet;
POST /api/system/update-peer-cache) and per-lab lines in the update progress ("tohum: PC-12, doğrulandı; 38 bilgisayara eşten dağıtılıyor"). PCs waiting for their lab's seed show "Tohum bekleniyor". - API and protocol for the peer cache.
deploy-updatereturnsseeds,waiting_for_seedandwith_peers, andupdate-progressreturns each device's peer role and a per-lab summary. New settingPEER_CACHE_SEED_TIMEOUT_SECONDS(600).- Optional
peersinupdate_agent, anX-Agent-Peer-Cacheheader andpeer_cacheinserver_info.features. The agent's peer cache contract is indocs/agent.md.
- Panel: Sistem → Modüller (superadmin).
- Each module shows its organisation state, its dependencies and the labs that differ, with a switch for the organisation setting. A module whose dependency is off shows as off, with the reason.
- Each module has a drawer with the organisation setting, what stops while it is off, and Kurum ayarı / Açık / Kapalı for every lab.
- Before anything turns off, the panel shows what will happen and asks to confirm: dependent modules that turn off too, remote-screen sessions that close, and pending tasks that are denied.
- Kurulum profili shows the current profile and applies Okul laboratuvarı or Kurum from a preview, optionally deleting lab-specific settings.
- API: new
GET /api/modules/{id}/preview.GET /api/system/install-profile/{name}also returnsvision_sessions_closedandtasks_deniedand takesreset_labs.
- GLPI export (Sistem → Entegrasyonlar, superadmin;
docs/integrations/glpi.md).- Sends computers (name, serial number, UUID, mapped location), installed software, helpdesk tickets and their public replies to GLPI's REST API. It runs on a schedule (daily, every 12 or 6 hours) or with Şimdi eşitle.
- Off by default. The app and user tokens are stored encrypted and never returned.
- Records are matched through a link table, then by BIOS serial number and SMBIOS UUID. POps never guesses between several matches, sends only changed records, and never deletes GLPI items except the software links it created.
- New
.envsettingsGLPI_ALLOW_PRIVATEandGLPI_CA_FILE; migration0029(glpi_links); endpoints under/api/system/glpi.
- Agent: exam mode.
exam_modelimits the PC's network to the POps server, DNS/DHCP and an allow list of host names, addresses and CIDR ranges (at most 50). It uses its own firewall rule group, independent of quarantine.- The tray shows a banner with the message and the end time. Up to 50 listed apps are closed. The exam ends at
untileven without the server. - The agent answers every
exam_modewithexam_state(enabled,since,until) and reports it once per connection to servers that listexam_mode. - New capability
exam_enabled(MSIEXAM_ENABLED, on by default; the server can only switch it off). Switching it off ends a running exam, and while it is offexam_modeis refused withcapability_denied. - The agent announces
examinX-Agent-Features. Events 1110–1112.
- Agent: file transfer.
file_pushdownloads a file only from the server's one-time/api/files/<id>/download?t=…URL. It checks the size and SHA-256 and writes the file only to the public desktop orC:\POpsData\inbox\<date>, under a cleaned name;.lnk/.url/.scronly when allowed.file_pulluploads a file the admin asked for, with a reason. Never fromC:\POpsData\secure, from other users' profiles only when explicitly allowed, never over the size limit; symbolic links are resolved first.- The result is reported as
file_resultwithoutcomedone,rejectedorfailed. The PC user is told in the tray; events 1120 and 1121. - New capability
files_enabled(MSIFILES_ENABLED, on by default; reported incapabilities). While it is off, a request is refused withcapability_deniedcarrying thetransfer_id. The agent announcesfilesinX-Agent-Features.
- Agent: winget packages. The agent implements
winget_install, announced with the newX-Agent-Features: wingetheader.- It installs a winget package as LocalSystem without a shell, only when the local terminal capability and the lab's deploy module are on.
- It validates the package id and version itself, answers -7 when winget is missing, and reports winget's own exit code.
- Agent tests read the shared protocol vectors in
docs/protocol. Every server-to-agent example is handled, agent messages validate against the JSON Schemas with only documented fields, the signed update vector verifies with the test key only, and the agent-to-server examples match what the agent sends. - Docs: Vision on the secure desktop (
docs/vision.md).- It covers what happens during UAC prompts and on the lock and sign-in screens, and why they are not captured today.
- It sets out the design a safe implementation would need (a SYSTEM helper in the user's session, a SYSTEM-only pipe, consent and audit, a threat model, a lab test plan) and the decisions left for the owner.
- Fuzzing with Atheris. Four targets in
fuzz/: the agent WebSocket handler, the request models, the signed release manifest and the notification settings. AfuzzCI job runs each for 60 s; seedocs/fuzzing.md. - File transfer (server and panel). An admin can send a file to PCs and fetch a file from a PC. In the device panel, Diğer has Dosya gönder (pick or drop a file up to 200 MB, destination Ortak masaüstü or POps gelen kutusu, a reason, and "çalıştırılabilir dosyaya izin ver" for
.lnk/.url/.scr; with upload progress) and Dosya al (full path, largest size 10/50/200 MB, a reason; a superadmin can also allow other users' profiles). Dosya gönder is also in the action bar menu of Cihazlar and Sınıflar for the selected PCs; PCs that are off or have no file transfer are skipped and listed. The panel's new Dosya aktarımları list shows direction, name, size, status, who, when and why, with İndir for a fetched file. Server:POST /api/files/push,POST /api/files/pull,GET /api/files,GET /api/files/{id}/content, and for agentsGET /api/files/{id}/downloadandPOST /api/files/{id}/upload; agent messagesfile_push,file_pullandfile_result, capabilityfiles_enabledincapabilities, featurefile_transferinserver_info(schemas indocs/protocol). Each PC gets its own transfer and a one-time token (1 hour, stored as a hash) bound to that PC; the agent endpoints always need the device secret, and a wrong, used or expired token or another PC's secret gets 404. Sending, fetching and downloading need an admin panel session (API tokens are refused); every send, request, received file, download and agent result is in the hash-chained audit log (metadata only, never the content), and the tray's activity history shows that a file was sent or requested. Fetched files are kept 7 days, sent files until they are downloaded; files live inBackend/transfers(POPS_FILES_DIR, Docker volumetransfers), are not served and are not backed up. New module Dosya aktarımı (files, on by default). Migration0025_file_transfers(tablefile_transfers,clients.cap_files_enabled). The reverse proxy templates allow 200 MB bodies on the two upload paths. The Windows agent side comes with the agent team's release; until an agent reportsfiles_enabled, the server sends it nothing. - Exam mode (sınav modu) per lab. In Sınıflar → Sınıf işlemleri → Sınav modu…, an admin sets:
- the allowed addresses (domain, IP or CIDR, at most 50);
- a duration (40/80/120 min or an end time, at most 8 hours);
- a tray message, programs to block and a reason.
- The lab's agents then block all traffic except the POps server, DNS, DHCP and the allow list, and they leave exam mode at the end time even when offline. While an exam runs, the lab shows the time left and every PC's state: in exam, left, unreachable, not supported (old agent), waiting or refused. The exam is re-sent on reconnect and to PCs moved into the lab. It ends when an admin ends it, at the end time, when the lab is deleted or when the
exammodule is switched off. A PC that leaves early raises an audit entry and a notification. API:POST/DELETE/GET /api/v1/labs/{lab}/examandGET /api/v1/exams. Agent protocol:exam_modeandexam_state. Migration0024.
- Linux agent for Pardus and Debian (first version). The
pops-agent_<version>_all.debpackage runs on Debian 12, Pardus 23+ and Ubuntu 24.04. It uses the distribution's python3-websockets and python3-cryptography, with no venv or pip. The agent:- enrolls with the usual token and keeps a root-only device secret;
- talks TLS only, optionally pinned to the school CA;
- reports DMI identity, hardware inventory, installed packages and the signed-in user;
- runs remote commands as root with
/bin/sh, under the Windows limits, and keeps results until they are acknowledged; - applies the capability policy (switched off locally, or by the server, which can only switch off);
- updates itself from the signed release, with rollback.
- The panel shows each device's system (Windows/Linux), and Uzak komut knows Linux targets. Not yet built: screen view, quarantine, tray. See
Agent-Linux/README.mdand decision D-22.
- Deploy: winget packages. Dağıtım → Paket yükle → winget paketi adds a package from the winget community source. Pick it from a catalog of 69 school and office apps (searchable by name, publisher and category), or type any winget id with an optional version. winget installs it as SYSTEM, silently, for all users.
- The new step type
WINGET({"id", "version"}) also works throughPOST /api/v1/tasks. - Ids and versions are limited to letters, digits and
. + _ -. They are checked on the request, before dispatch and by the agent, which starts winget without a shell. - The server sends the new agent message
winget_installonly to agents that announceX-Agent-Features: winget. On other PCs the step is refused and nothing is sent; the run dialog warns how many selected PCs are affected. - winget's "already installed" and "restart pending" codes count as done, and common winget errors are shown in plain words.
- Endpoint
GET /api/v1/deploy/winget/catalog. Migration0027. Decision D-23.
- The new step type
- Vision v2 on the server and in the panel.
- Server: binary screen frames on
/ws/vision(18-byte header + JPEG, at most 2 MB, checked with the agent's rules; bad frames are dropped and counted in/metrics). They are relayed only to the session holder's Remote screen page, under the tunnel's own device ID. - Slow viewers drop frames rather than queue them: a full frame replaces what is waiting, and regions beyond 32 frames or 4 MB are dropped until the next full frame.
- Viewer commands: screen selection (
monitors,select_monitor) and quality, scale and frame rate (set_quality) are forwarded only from the admin holding the session. - Panel: the Remote screen page draws regions onto a canvas. It has a screen picker (one screen or all side by side), image quality, scale, a frame rate up to 10 and a live fps and kbit/s readout. Mouse input maps to the shown screen.
- Compatibility:
server_infolistsvision_binaryandvision_clipboard. Older agents keep sending JSON frames.
- Server: binary screen frames on
- Vision clipboard. Text, up to 64 KB, both ways. Only the admin whose "ask the user" session the PC user accepted can use it, and never in a mandatory session. Every transfer is audited (direction, length, admin, time, never the text) before the text is passed on.
- JavaScript unit tests (
tests/unit-js/, Node's built-in test runner, no dependencies) for the shared panel helpers (translation and plurals, escaping, time and duration formats, error texts) and the page-script helpers (CSV formula guard, page numbers, update status). CI runs them in the Dashboard checks job (node --test tests/unit-js/*.test.mjs); how to add page scripts and tests is indocs/dashboard.md. - CI: documentation states the current versions.
tools/check_docs_versions.pyruns in the Version consistency job and fails when README, ROADMAP,docs/, SECURITY.md, CONTRIBUTING.md, the issue templates or the release notes call a version other thanVERSIONthe latest, call an already released version the next one, or name such a version in README or ROADMAP at all. It also fails when they give a Python or PostgreSQL minimum other than the one inBackend/requirements.txtand the CI migrations job, or a .NET runtime requirement that does not fit the self-contained .NET 10 agent. Sentences about already released versions count as history. A line can opt out withdocs-versions: ignore. - Panel: English for Sistem, Ayarlar, Uzak komut and the sign-in page. Every panel page can now be shown in English. When no language has been chosen yet, the sign-in page follows the browser's language and stores the choice. A Türkçe / English switch under the form works without JavaScript and keeps a pending 2FA step.
- Panel: server texts with values are shown in English too. Examples: a scheduled task's last result ("Queued for 3 devices"), who created a task from a schedule ("admin (scheduled #1, run by hand)") and notification titles such as agent update results. Stored task titles show their scope in English ("Shut down · 3 selected computers"); lab and computer names stay as typed.
- Agent: updates download with BITS. The update MSI is fetched with BITS and resumes after network drops and restarts. A download still running after 15 minutes continues with the next update command. When BITS is unavailable the agent downloads directly as before. The signed size and SHA-256 are checked either way. A design for a lab-local peer cache (one download per lab) is in
docs/design/peer-cache.md. - Agent protocol as JSON Schema with shared test vectors.
docs/protocol/defines both agent WebSockets message by message (9 agent → server and 20 server → agent messages, plus the signed release manifest), with 51 example messages that the backend checks and the agent tests load (docs/protocol/AGENT_TESTS.md). Rules for a second agent: agent messages carrytype, server messagesaction; what exists today is protocol 1; optional behaviour is negotiated withserver_info.features; unknown fields and messages are ignored.server_infonow also sends"protocol": 1.Backend/tests/test_protocol.pyruns the real WebSocket handlers, task queue and endpoints with a fake database and fake sockets and fails on any message that does not match its schema. - Public read-only demo (
deploy/demo/): a Compose stack with PostgreSQL, the backend and a fake fleet on an internal network and the panel on 127.0.0.1:8180;seed.py(demo viewer, enrollment token, two weeks of history, licences, "POps Demo Okulu");reset.sh(nightly wipe and reseed);setup-host.sh(owner install with a 03:30 systemd timer); Virtualmin and.htaccesssteps. tools/demo_fleet.py: 50 fake school PCs in four labs plus two teacher PCs. They enroll with a token, follow a school calendar, report inventory, software and Windows Update status, raise DNS violations and help-desk tickets, and answer every command with a canned reply. They never execute anything.- Demo accounts: backend
POPS_DEMO_USERSmakes the listed accounts read-only (every request other than GET, HEAD and OPTIONS returns 403 "Demo hesabında değiştirilemez", including the account's own password and 2FA); panelPOPS_DEMO_LOGINshows the demo credentials on the sign-in page.Backend/tests/test_demo.pychecks every write endpoint in the route table. - Agent: Vision v2. When the server supports binary frames (
vision_binary), the tray captures with DXGI Desktop Duplication (GDI where it is unavailable) and sends only changed regions after a full frame, as binary WebSocket messages with an 18-byte header. The viewer can pick a screen or all side by side and set quality, scale and frame rate; the agent lowers quality instead of queueing when the connection is slow. Text clipboard (up to 64 KB) is shared both ways only in a session the PC user accepted; the tray says so and the event log keeps only direction and length (event 1100). Older servers keep the previous JSON frames. - API: versioned
/api/v1for integrations. Every HTTP endpoint under/api/...also answers under/api/v1/...(same handler, permissions and response; one middleware rewrites the prefix before routing)./api/v1is the stable surface for scripts and other systems; plain/apistays for the panel and agents. WebSockets are not versioned. Rate limits and request metrics count both forms together (decision D-21). - API tokens for automation. A superadmin creates, lists and revokes them in Ayarlar → Güvenlik → API jetonları (or
GET/POST /api/v1/tokens,DELETE /api/v1/tokens/{id}). A token ispops_+ 32 random bytes, shown once; only its SHA-256 hash and an 8-character prefix are stored (migration0022, tableapi_tokens). Role Görüntüleyici (viewer,GETonly) or Yönetici (admin), never superadmin, with an optional validity in days. Send it asAuthorization: Bearer pops_...; it needs noX-Requested-Withheader (cookie sessions still do). Tokens cannot use superadmin endpoints, manage users or tokens, use 2FA, or open remote screen and remote input. Expiry and revocation apply on the next request. What a token does is recorded astoken:<name>(tasks, audit log, event log); creating and revoking tokens is audit-logged. - API: REST names for the RPC-style endpoints under
/api/v1, calling the same handlers: labs (GET/POST /api/v1/labs,PATCH/DELETE /api/v1/labs/{lab_name}, main PC, layout, wake), devices (move, rename, wake, quarantine, bypass code), settings (task concurrency, auto-enroll), tasks, packages, files, agent policies, scheduled tasks, licences and tickets. The full list is indocs/api.md. - OpenAPI specification in the repository:
docs/openapi.json(paths under/api/v1), generated bypython tools/export_openapi.py; CI fails when it is out of date. The running server still serves no/docsor/openapi.json. - Panel: English interface — Dağıtım, Politikalar and Uzak ekran (Deploy, Policies, Remote screen): packages and the run dialog, policy editing and the sample privacy notice (a natural English text, not a word-for-word copy), the Vision wall, consent and session dialogs, and diagnostics. Data sent to the server, such as task titles, stays Turkish.
- Panel: English interface — Kayıtlar, Raporlar and Destek talepleri (Logs, Reports, Help desk), including filters, drawers, dialogs, licences and Windows updates. The Logs and Hardware CSV exports use the interface language for column headers and the file name; the server's report CSVs keep their language-neutral column names.
- Panel: English interface — Cihazlar, Sınıflar and İşlemler (Devices, Labs, Jobs): the device list and its CSV export, the lab map and layout editor, lab actions, and jobs and scheduled tasks with their drawers, dialogs and messages. Lab names, task titles and other data sent to the server stay as entered.
- Panel: end-to-end tests in a real browser (Playwright, Chromium), run by the new CI job "Panel end-to-end". Every page is opened at desktop (1440×900) and phone (390×844) width and must load without console errors, without requests to any other host and without horizontal scrolling on a phone. The main flows are covered too: sign-in and sign-out, device search and details, creating, renaming and deleting labs, task status, paging and filters on Kayıtlar, the Sistem tabs and charts, the organisation name and queue limit in Ayarlar, and what a viewer may see. The tests start their own backend and panel on an empty test database; see
docs/testing.mdto run them locally. - Agent: log retention. The service deletes
C:\POpsLogs\POps_*.logandmsi-*.logolder than 30 days, and the oldest ones while the folder holds more than 200 MB, at start and daily. Today's log is never deleted; the folder's permissions are unchanged. - Agent: reports update stages (
update_progress): received, downloaded, verified, updater started, "Windows Installer busy, waiting (n/5)" and installing, plus the reason when it refuses an update. The updater writes its stages toC:\POpsData\update-progress.jsonand the service forwards them; only servers that list the feature receive them. The panel shows them under Sistem → Güncellemeler (server side in this release). - Panel: agent update stages. Between sending an agent update and its result, Sistem → Güncellemeler shows per PC the stage the agent reports and how long ago: Alındı, İndirildi, Doğrulandı, Kurulum başladı, "Windows Installer meşgul, bekleniyor (2/5)", Kuruluyor, or "Reddedildi: ". Agents report them with the new
update_progressmessage (see docs/api.md); agents up to 0.1.21 send none and show "Kuruluyor" as before, with "Ajan ilerleme bildirmiyor (eski sürüm olabilir)" after 3 minutes. An agent's refusal (bad signature, version not newer, download failed, …) now ends the update in the panel with its reason, an audit entry and a notification instead of waiting 20 minutes for silence.POST /api/system/update-progressalso returnssent_at,stage,detail,attempt,of,stage_atandnow. Migration0023_update_progress.sql. Older servers ignore the message. - Docs: Turkish guides for schools in
docs/tr/: "Neden POps?" (what POps solves and what it does not, KVKK and transparency, cost, working without internet), "POps ve Veyon birlikte" (who does what, installing both on the same PCs without port conflicts, a typical day; with a light and dark figure fromassets/readme/make_figures.py), "Pilot okul kurulumu" (a checklist for one lab of 10 PCs, what to measure for 2–4 weeks, a feedback form) and a case study template. README.tr links them; README lists them as "Turkish guides for schools". - Docs: code signing policy (
docs/code-signing.md) for Authenticode signing through the SignPath Foundation: what is signed and never signed, how a release is built and approved, roles, key custody and how to verify a download. The application is still to be made; the binaries are not Authenticode-signed yet. - Docs: GLPI export design note (
docs/integrations/glpi.md): sending inventory and helpdesk tickets to GLPI, with field mappings, sync direction, conflicts and authentication. ROADMAP lists it under Next → Integrations. - Docs: "Linux and Pardus" in README and README.tr; ROADMAP names Lider Ahenk integration as an alternative to a Linux agent.
- GitHub: issue forms and contributor onboarding. Bug report and feature request forms replace the Markdown templates; questions go to Discussions and security reports to SECURITY.md. The pull request template has a checklist (tests, lint, docs, CHANGELOG, no secrets, transparency), and CONTRIBUTING has a "Good first issues" section.
- Panel: English interface (in progress). Türkçe / English at the bottom of the sidebar switches the panel language for this browser (cookie
pops_lang, kept for a year; the default stays Turkish). Translated so far: the sidebar, search, job center and notifications, page titles, dialogs, toasts and error messages (including the most frequent server messages), relative times and dates, the device actions and the device detail panel, task states and failure reasons, the event wording shown on Kayıtlar, and Kontrol merkezi. Other pages are being converted and show Turkish text until then. Translations live inDashboard/lang/en/(one file per page); CI checks them withtools/i18n/check_i18n.py. How it works and how to convert a page:docs/i18n.md.
Changed
- Backend code layout.
/ws/agentis split into small functions with one handler per message type, and the system endpoints moved fromsystem_routes.pyto the packagepops/routers/system/.system_routesstill works as an import name. No behaviour or API change. - Counts across all workers. Diagnostics,
/metricsand the overview count connected agents and panels across all workers; diagnostics shows aclusterblock when Redis is on. - New backend dependency:
redis7.4.1. - CI: the agent's nullable baseline only shrinks.
tools/check_nullable_baseline.py(CI's version job) compares the agent files that carry#nullable disablewith the fixed list intools/nullable_baseline.txt(53 files: 41 in the agent service, 9 in the shared library, 2 in the updater, 1 in the MSI custom actions).- A file outside the list that turns nullable off fails CI; new files must be nullable-clean.
- A listed file that is gone or no longer has the line fails too, until its entry is removed, so the list shrinks as files are cleaned. A product project without
<Nullable>enable</Nullable>also fails.
- Agent: a mandatory Vision session that starts while the PC is locked is no longer silent (owner decision 5,
docs/vision.md).- The countdown still runs on the hidden desktop, but the tray records that the user's desktop was not on screen when the session started.
- As soon as the user's desktop returns, the tray shows a balloon and a banner at the bottom of the screen that the user cannot close ("Ekranınız Bilgi İşlem tarafından izleniyor (oturum bilgisayarınız kilitliyken başladı)", with the admin, the reason and the session ID). The banner stays until the session ends, and no picture of the user's desktop is sent before it is on screen.
- The PC writes event 1150 to the Windows event log and posts an
agent.vision_locked_startentry to the server's event log (existingPOST /api/logs; no protocol change). - Routine (consent) sessions still wait for the user's answer.
- The tray now also stops capturing when it loses its connection to the service.
- Real timestamps. The older tables' text dates become
TIMESTAMPTZ(migration0031), read in the server's time zone (POPS_TZ, else the system zone). The API returns ISO 8601 with an offset; CSV keeps readable local time. Audit chains written before the update still verify. - The deploy backs up the database before a rewriting migration.
pops-deploy-backendrunspg_dumpbefore any migration marked-- pops: dump-before. It keeps at most 3 dumps, respectsKEEP_BACKUPSand checks free space first.- Upgrading: reinstall
Installer/server/pops-deploy-backendto/usr/local/sbin/pops-deploy-backendbefore deploying.0031rewrites large tables (logs, tasks, audit), so the update takes longer. - To roll back after this migration, restore that dump together with the old code (
docs/deployment.md). - If the old text dates were written in a zone other than the server's, set
POPS_TZbefore migrating.
- Upgrading: reinstall
- New agents get Kapat and Yeniden başlat as
powermessages, not as ashutdowncommand; older Windows and Linux agents still get the old command. Sign-out, lock and messages are refused with -8 for agents without the feature, and nothing is sent to them. - Power and message tasks are queued apart from commands. They don't use up the concurrency limit, don't depend on the remote command module, and expire after 15 minutes if they are not sent. Mesaj gönder no longer uses the Windows
msgcommand. - API: unknown fields in a request body are refused (
422,extra_forbiddenwith the field name) on every panel and integration endpoint.- Before, most endpoints dropped them silently and ran with defaults: a misspelt
labonPOST /api/modules/{id}turned the module off for the whole organisation. - Bodies sent by agents still ignore unknown fields, so an older server keeps a newer agent's data.
/api/remote_inputstill accepts its top-level input fields.
- Before, most endpoints dropped them silently and ran with defaults: a misspelt
- Audit log: module changes also record the previous setting, and install-profile changes record the modules they changed and the lab settings they deleted.
- Agent: nullable reference types. The agent service, the shared library and the MSI custom actions now build with nullable reference types on, as the tray, watchdog and updater already did.
- The 49 files that were not nullable-clean on 5 October keep a
#nullable disableline: a baseline that only shrinks, like the warnings list inAgent/.editorconfig. - New files must be nullable-clean: a nullable warning fails the build, now also in the custom actions. No behaviour change.
- The 49 files that were not nullable-clean on 5 October keep a
- Agent tests are named after the component they test (for example
HardwareBindingTests.cs,ResultSpoolTests.cs) instead of the review round that added them. No test was added, removed or changed. - Agent: Worker.cs split, step a0. A pure move (1919 → 1717 lines) toward one handler per message type; the design is in the PR (#122). No behaviour change.
- Backend tests run under pytest.
python -m pytestrunsBackend/tests(configuration: the rootpytest.ini; pytest comes from the hash-locked.github/requirements/pytest.lock).test_units.pyis a pytest module, one test per function, so a single test can be selected (-k) and JUnit output written (--junitxml). The older script tests are collected byBackend/tests/conftest.pywithout being imported: each runs in its own process as one test, a failure lists the checks that failed, scripts that need a running server carry theintegrationmarker and keep the order CI used, and a new script needs no registration. CI andBackend/tests/run_local.shcall pytest instead of listing the scripts; how to run, select and add tests is in CONTRIBUTING.md. - Agent updates per platform. A signed release carries the MSI and the
.deb. fetch-release stages both; deploy-update copies both to/updates/and skips PCs whose platform has no package (skipped_no_package). Migration0026addsclients.platform. - Agent results: a
[REDDEDİLDİ]result with exit code -5 now marks the taskDenieddirectly. /api/devicesreturnsagent_features. Closing the Dosya dağıtımı module in a lab denies its pending winget tasks.- The Vision tunnel survives a single bad message. It no longer closes on one message the server cannot process; as on
/ws/agent, 20 in a minute close it. - Panel and API: the device list is cheap to poll.
GET /api/devicesreturns a weakETag, and a matchingIf-None-Matchgets304without a body.?since=<version>returns only what changed:changedrows,removedIDs andseen(last_seenrefreshes). It returns the whole list withfull: truewhen the change log (10 minutes or 5,000 changes) cannot answer.- Panel sockets opened as
/ws/panel?topics=devicesget{"type": "devices_changed", "version": n}at most once a second. - The panel's device pages fetch changes as soon as they are told, and poll every 30 s instead of 5 s while the socket is open.
- With 2,000 agents, an open tab now pulls 76 KB a minute instead of 14.4 MB when nothing changes. A device going offline shows within about a second. Measurements:
BENCHMARKS.md.
- Panel: page scripts. The JavaScript of Raporlar and Kayıtlar moved out of the PHP pages into
Dashboard/assets/pages/reports.jsandlogger.js. The pages have no inline script, and PHP values reach the script through a JSON block. Behaviour is unchanged.check_html_sinks.pyandcheck_i18n.py --missingalso coverassets/pages/. - Docs: README and README.tr match
main. They link the public read-only demo (demo.pashacore.com.tr, user and passworddemo) and have feature rows for API v1 and API tokens, the organisation's name and logo, both panel languages, the Sistem charts and agent log retention. They also describe the stable and preview self-update channels, agent update stages and BITS downloads, and Vision v2 as agent side only, with the panel viewer still to come. The test and supply-chain summary and the roadmap paragraph are current; the paragraph no longer calls 0.1.14 the next round. - Docs: ROADMAP. API v1, the panel end-to-end tests, the English interface, the protocol schema, the demo and this week's agent work are listed as done. Code signing through the SignPath Foundation is the first item under Next.
- Docs: positioning.
- POps is Apache 2.0 (OSI-approved), while Tactical RMM's licence is source-available and restricts commercial services.
- POps works with GLPI instead of competing with it; the export is a design note.
- A section on Pardus, ETAP and Lider Ahenk.
- Docs: release channels.
CHANNEL=releaseis the stable channel: the newest release tag, weekly releases, SSH-signed tags.CHANNEL=mainis the preview channel, for test servers. Seedocs/self-update.mdanddocs/deployment.md. - Docs: agent contributors. CONTRIBUTING describes the agent warnings gate and the
Agent/.editorconfigbaseline. - Panel: Vision diagnostics and Remote command quick-action titles are translated on every page that lists jobs, not only on the page that sent them.
- Agent: warnings gate. The agent, tray, watchdog, updater and shared library build with the .NET 10 recommended analyzers and treat warnings as errors. The warnings that existed on 5 October are listed per file in
Agent/.editorconfig, and any new one fails the build. 60 warnings were fixed, including all of them in the service'sWorker.csand the tray pipe code. - Panel: browser configuration object renamed to
window.POPS_API(assets/pops_config.js). Upgrading: the file ships with the panel and is replaced on update; if you edited it locally, rename the global in your copy. - API: the old RPC paths are deprecated but keep working (
/api/create_lab,/api/move_pcs,/api/set_concurrent_limit,/api/deploy_orchestration, … — the list is indocs/api.md); the panel still uses them. Unlike/api/set_main_pc, the REST name does not toggle:PUTsets the main PC,DELETEclears it. - API:
task_sequence.POST /api/deploy_orchestration(andPOST /api/v1/tasks) acceptstask_sequenceas well astaskSequence; sending both is422. - Server: the large-upload rule of the reverse proxy also covers
/api/v1. The nginx and Apache templates match^/api/(v1/)?(upload|files|system/upload-release)$. Upgrading: an existing server keeps its own site configuration; to upload files over 8 MB through/api/v1, change that line to the new pattern. Plain/api/uploadis unchanged. - Accounts: user names can no longer start with
token:(reserved for API tokens in the logs). - CI: shellcheck also checks
docker/dashboard-entrypoint.shandBackend/tests/run_local.sh(#82, thanks @GhostCoder6969 — the first outside contribution). - An agent update is not sent twice.
POST /api/system/deploy-updateskips a PC whose update to the same version was sent less than 15 minutes ago, or that reported a stage in that time (the agent ignores a second command while its update lock is fresh), and lists it inalready_pending; the panel says "N bilgisayara zaten gönderildi, kurulum sürüyor" and keeps following it. The 20-minute "no result" notice counts from the last reported stage.
Fixed
- Agent: an unreadable-hardware heartbeat follows the protocol schema. When the hardware could not be read, the heartbeat now carries an empty
dna_payloadobject instead of null. - Agent: Vision shows a notice while the secure desktop is up.
- During a live session, a UAC prompt, Ctrl+Alt+Del, the lock screen or the sign-in screen no longer leaves the viewer on a frozen picture. The tray sends a "Güvenli masaüstü etkin" picture instead, every 5 seconds, and resumes the live picture when the user's desktop returns.
- With Vision v2, capture no longer stops for good after the first UAC prompt or lock. The secure desktop itself is still neither shown nor controlled.
- Wrong-typed fields in an agent's first message are ignored, as the protocol rules say. A wrong-typed
dna_payload,hardware,capabilitiesorhostname, or a number like1e999inagent_health, no longer closes the connection (1011). - A malformed signed release manifest is rejected with 400 instead of failing with 500. This covers a manifest that is not a JSON object and one with malformed artefact entries.
- The agent policy drops domain entries that contain whitespace or control characters. A NUL used to make saving the policy fail.
- Quarantine on a Linux PC answers 409 instead of marking it locked. An unsupported quarantine reported by an authenticated Linux agent clears the pending lock.
- Docs: stale facts. README no longer says there are no API tokens or that the panel is Turkish only. The FAQ,
docs/dashboard.mdand the Turkish "Neden POps?" guide no longer say English covers part of the panel. Decision D-15 no longer implies the panel loads fonts and icons from CDNs. CONTRIBUTING no longer lists the removed POpsVision source.docs/security.mdlists the sign-in branding endpoints among those reachable without signing in. The pilot guide writes the MSI log toC:\Windows\Temp. Troubleshooting shows the agent's current message for an unreadable configuration. - Docs: agent behaviour that was only in the CHANGELOG is now in
docs/agent.mdand troubleshooting: update stages andupdate-progress.json, log retention inC:\POpsLogs, event 1090 for an unreadable configuration, and the tray pipe that stays open while the server is unreachable. SECURITY.md and the architecture pages mention API tokens and hash-locked dependencies. - Kontrol merkezi: viewers see "Göster", not "Güncelle", for old agents. A viewer cannot update agents. The tile and the attention item already opened the device list.
- Docs: Vision channel authentication.
docs/api.mdsaid/ws/visionaccepts an enrollment token; it accepts only the device secret. - Apache template: WebSocket rule.
Installer/server/apache-htaccess.exampleforwarded/ws/panelas/ws/because the path came from the wrong condition. Upgrading: if yourDashboard/.htaccesshas theUpgradecondition after the/ws/path condition, swap them (sites with a vhostProxyPass /ws/were not affected). - Agent: an unreadable configuration is reported. When
appsettings.jsoncannot be read or has no validServerUrl, the agent still falls back tohttp://127.0.0.1:8000, but now logs an error, writes Windows event 1090 and shows "POps - yapılandırma okunamadı" with a warning icon in the tray instead of looking healthy. - Panel: on phones the scheduled tasks table scrolls inside its card instead of widening the page.
- Panel: viewers no longer see pages they cannot open. A viewer whose permission list still contained Dağıtım, Uzak komut or Ayarlar (for example an admin demoted to viewer) saw those pages in the menu and the Ctrl+K search but got "Yetkisiz Erişim". They are now hidden for viewers.
- Panel: İşlemler no longer asks for the admin-only scheduled-task list as a viewer every 30 seconds (it only produced 403 errors in the browser console); the Zamanlanmış tab is hidden for viewers.
- Docs: stale facts. ROADMAP no longer lists pentest findings F9 and F11 as open (closed in 0.1.4 and 0.1.13); the FAQ gives the measured capacity (5,000 agents on one process) instead of 1,000; the MSI install examples write their log to
C:\Windows\Temp, which always exists, instead ofC:\POpsLogs, which a fresh PC does not have yet (msiexec would refuse with 1622);docs/api.mdno longer links a design note that is not in the repository. - Agent: offline bypass works while the server is unreachable. The tray pipe stays open for the whole life of the service; before, it was closed after every lost server connection until the next attempt, and an offline code typed in the lock screen during that wait (up to a minute, 10 minutes after a
4409) was dropped silently. The lock screen now says when a code could not reach the service. Needs the agent from the next release. - Docs: a broken link to the agent setup section in CONTRIBUTING; getting-started no longer says the panel loads fonts and icons from CDNs.
Security
- Agent: update packages may come from lab peers. The signed manifest still comes only from the agent's own server. The package may also come from PCs in the same subnet that the server lists, and is accepted only if its size and SHA-256 match the signed manifest. A PC listens on TCP 8817 (local subnet only, at most 2 hours) only after the server asked for it with
peer_cache: true. Switch it off per PC withPEER_CACHE_ENABLED=0. - Agent folders: owner checked on every start. If the data,
secureor log folder is owned by another account (for example a student who createdC:\POpsDatabefore the agent was installed), the service and the MSI set the owner to SYSTEM when they lock the folder; before, that account could open the permissions again. - A scoped account cannot reach another school's devices. That holds for lists and direct ids, through the panel, the REST API, API tokens and the panel WebSocket, including the device-list version and
devices_changed. - The peer cache is off by default, and a PC listens only when told.
update_agentcarries"peer_cache": trueonly while the setting is on, and only to the PCs that take part in a staged rollout. Without it the agent keeps no package, starts no cache server and opens no port. The README's "no inbound ports on PCs" holds unless an admin turns the peer cache on. - Directory and OIDC sign-in are verified end to end.
- Directory sign-in works only over LDAPS or StartTLS, with the certificate and host name verified.
- OIDC uses the code flow with PKCE, state and nonce. The ID token's signature (asymmetric algorithms only), issuer, audience, expiry and nonce are checked.
- A one-time ticket bound to the starting browser prevents login CSRF, and redirect targets come only from the configured redirect URI.
- Local accounts are protected from directory and OIDC identities. Local accounts never reach the directory, the first local superadmin stays local, and a directory or OIDC identity cannot take over a local account. Disabled, removed or unmapped directory accounts are refused and their sessions end.
- Provider secrets stay secret. They are encrypted at rest, never returned, and not reused when the server, connection or CA changes. Every change is audit-logged without secrets, and 2FA still applies.
- Notes and message texts never reach a shell. They go as JSON fields. The server strips control and bidirectional characters, and the note for old agents keeps only characters that are safe inside quotes.
- Messages need a person. They require a panel session (API tokens get 403), and audit records store only the length and first 60 characters of a note or message.
- CI installs every Python tool from hash-locked files (
.github/requirements/*.lock, generated and checked withtools/backend_lock.sh, refreshed on Dependabot PRs). No unpinnedpip installis left in the workflows. - The Docker base images are pinned by digest (
python:3.12-slim,php:8.3-apache). Dependabot proposes the new digest of the same tag weekly. - Workflow tokens are read-only at the top level. CodeQL's
security-events: writemoved into its job, and the remaining write grants say why they are needed. vision_rejectedis forwarded to the panels with the connection's device ID. Before, any connected agent could end an administrator's remote-control session on another device.- An agent string containing
\u0000or a lone surrogate no longer breaks database writes. Before, such a task result was never stored and was resent forever, and one such heartbeat dropped the batched heartbeats of every device. - Exam mode is a network restriction and a notice, not proctoring. A local administrator can switch it off (the
examcapability), and the panel then shows the PC as left or refused. Seedocs/security.md"Exam mode". - Vision commands and frames are bound to the session and the device. Viewer commands and clipboard text reach the agent only from the admin holding the session. Binary frames, screen lists and clipboard text are always filed under the tunnel's authenticated device.
- Remote screen frames are filed under the tunnel's own device.
/ws/visionforwarded thehw_idthe agent put in a frame, so an enrolled agent could put frames into another device's tile for an admin who had a session open on it. The server now sets it to the device that authenticated the tunnel. - Backend dependencies are hash-locked.
Backend/requirements.lockpins every dependency, indirect ones included, with the SHA-256 of each file;install.sh,pops-deploy-backend, the Docker image and CI install it withpip install --require-hashes, so a changed file on the package index is refused before anything is installed. Checkouts without the lock fall back torequirements.txt. Regenerate it withtools/backend_lock.shafter changingrequirements.txt(CI checks it); Dependabot PRs get it from thelock-refreshworkflow. A native server uses the lock once/usr/local/sbin/pops-deploy-backendis updated.