Security & Trust
How psLens protects your PeopleSoft environment: read-only by design, table whitelist, dedicated instance per client, no direct database access.
psLens gives your team a window into PeopleSoft metadata. It cannot write to your database, it cannot query outside a whitelist you approve, and your instance does not share anything with anyone else’s.
The Short Version
- Read-only by design. psLens never writes to PeopleSoft. There is no code path that issues
INSERT, UPDATE, or DELETE against your environment. - No direct database credentials required. psLens connects to PeopleSoft through the SWS framework, which exposes a bounded REST API. Your database passwords stay on your side.
- Query surface is whitelisted. psLens can only query PeopleTools metadata tables that are explicitly allowed. Anything off-list is rejected before it reaches PeopleSoft.
- Dedicated instance per client. Each customer gets their own isolated deployment. No shared tenancy, no shared database, no cross-customer blast radius.
- Your PeopleSoft business data stays in PeopleSoft. psLens stores alert history and report output only, nothing else.
- Nothing is cached in the browser. Pages render server-side and stream over SSE. psLens writes nothing to
LocalStorage, SessionStorage, or IndexedDB; closing the tab clears everything.
For the high-level picture of how psLens is deployed and how it talks to PeopleSoft, see the Architecture Overview. This page focuses on the security implications of that design.
How Queries Reach PeopleSoft
%%{init: {"flowchart": {"htmlLabels": true, "padding": 16, "nodeSpacing": 50, "rankSpacing": 60}}}%%
flowchart TD
APP["psLens app<br/>(dedicated instance per customer)"]
SWS["SWS framework<br/>(installed in your PeopleSoft environment)"]
DB[("PeopleSoft database<br/>(read-only)")]
APP -- "HTTPS + basic auth<br/>(token in config.yaml or env var)" --> SWS
SWS -- "psoftQL, scoped to<br/>whitelisted tables" --> DB
classDef ps fill:#e8f4fd,stroke:#0d6efd,stroke-width:2px,color:#000
classDef ext fill:#fff5e6,stroke:#fd7e14,stroke-width:2px,color:#000
class APP ext
class SWS,DB psEvery query psLens issues flows through this path. There is no second channel. If the SWS framework is not installed, psLens cannot see anything.
Read-Only by Design
psLens reads metadata. It does not change anything in PeopleSoft, and it has no code path that could:
- No administrative actions. Reports, alerts, and metadata browsing are all read operations.
- No PeopleCode execution. psLens inspects configuration; it does not run it.
- No project migration, no security grants, no user creation.
If you want to change something you see in psLens, you still do that in App Designer, PIA, or your existing change-management process.
Query Surface: The Table Whitelist
The SWS framework only responds to queries against tables that are explicitly whitelisted. psLens ships knowing which PeopleTools metadata tables it needs: PSRECDEFN, PSPNLDEFN, PSCLASSDEFN, PSAUTHITEM, process scheduler tables, Integration Broker tables, and similar (a known, published list).
A query that references any table outside the whitelist is rejected by SWS before it touches the database. This is enforced on your side of the connection, not the psLens side. Even if psLens were misconfigured, it could not reach into payroll, HR, financials, or any other transactional data.
When you add psLens to an environment, you see the whitelist and approve it. You can review or narrow it at any time.
Credential Handling
- The SWS endpoint uses HTTP basic auth over HTTPS.
- The auth token is stored in psLens
config.yaml or injected through environment variables at deployment time. - No PeopleSoft database username or password is ever needed by psLens.
- No single-sign-on tokens, session cookies, or end-user credentials are stored.
Rotating the SWS auth token is straightforward: rotate on the PeopleSoft side, update the psLens config or env var, restart the instance.
Deployment Isolation
Every psLens customer gets a dedicated deployment:
- One instance per customer. No shared app, no shared database, no shared filesystem.
- Hosted on fly.io by default, with deployment options to match your security requirements.
- Your data does not traverse a shared service. There is no psLens SaaS multi-tenant backend.
- If you prefer to host psLens yourself in your own cloud account or on-prem, that is supported — see installation for bare-metal and Docker options, including air-gapped environments.
What psLens Stores
psLens only persists two categories of data, and both stay inside your dedicated instance:
- Alert history. A rolling record of alerts that fired, for trend review. Retention is configurable; defaults to a short window because alerts are meant to surface current issues.
- Report output. The Markdown output of reports you have run, kept for 90 days so you can revisit audit findings or compare runs. See reports.
psLens does not copy PeopleSoft business data (employee records, financial transactions, HR data) into its own storage. Reports pull what they need at run time and summarize it; browsing and search fetch metadata on demand and display it.
What psLens Does NOT Do
- It does not write to PeopleSoft.
- It does not require a direct database connection.
- It does not store PeopleSoft business data outside of alert and report output.
- It does not share a database or application instance across customers.
- It does not phone home. Your deployment talks to your PeopleSoft environment; it does not report back to Cedar Hills Group.
Going Deeper
This page is the short version. If you’re preparing a vendor security review or filling out a SIG / CAIQ, these pages cover the topics your reviewers will ask about: current state, gaps, and roadmap, stated plainly.
- Code & Supply Chain. What code runs, source-review under NDA, dependency posture, vulnerability disclosure.
- Authentication & Access. Magic-link login today, SSO via reverse proxy, native SSO on the roadmap, why there’s no in-app RBAC.
- Data Handling & Logging. What is stored, encryption at rest and in transit, personal data handling, audit logging.
- Deployment & Operations. Network requirements, sizing, backup, upgrade, DR, monitoring.
- Compliance & Vendor. SOC 2 posture, GDPR / DPA, sub-processors, business continuity, source escrow.
- What SWS Installs in PeopleSoft. The objects, roles, and Integration Broker setup added to your environment, for the reviewer approving the install.
If a quick Q&A is all you need, the FAQ has one-paragraph answers cross-linked to the deeper pages above.
Questions Before a Demo?
If you have specific security or compliance questions (data residency, SWS role permissions on your PeopleSoft side, how to integrate with your existing SSO for the psLens login layer) raise them on the demo call or email chris.malek@cedarhillsgroup.com and we will answer in writing before you commit to anything.
1 - What SWS Installs in PeopleSoft
The objects, roles, and Integration Broker setup the SWS framework adds to a PeopleSoft environment. Written for the admin, DBA, or security reviewer who has to approve the install.
The SWS (Secure Web Services) framework is the PeopleSoft-side component psLens queries through. This page lists what installing it actually changes in your environment, so the person approving the change can see the full footprint before anything is migrated. The authoritative installation guide lives at sws.books.cedarhillsgroup.com; this page is the summary for a security review.
The Install in One Paragraph
SWS is delivered as a standard App Designer project. You import it into a development environment first, test it there, and migrate it to TEST and PROD through your normal change-management path, the same way you move any other project. There is no installer, no agent, and no software on the database server. Plan for under an hour of PeopleSoft admin time for the first environment.
What the Project Contains
Roughly 100 PeopleSoft objects, all namespaced with the CHG_ prefix (C_ for records):
- 9 records for configuration and logging, including the whitelist tables described below
- 32 fields supporting those records
- 4 pages for administration and testing
- 6 application packages containing the framework’s PeopleCode
- 2 service operations:
CHG_SWS_GET and CHG_SWS_PSOFTQL_POST - 2 roles:
CHG_SWS_ADMIN (setup pages) and CHG_SWS_USER (API access)
The full object manifest is in the SWS installation docs. The project ships with sample data for testing; the SWS docs are explicit that sample data is not meant for production systems.
Security Objects and the Service Account
psLens connects as a PeopleSoft operator you create for it (for example PSLENS_API). That account:
- holds the
CHG_SWS_USER role, which grants access to the API and nothing else - authenticates to the service operations with HTTP basic auth over HTTPS
- is an ordinary PeopleSoft account, so your existing controls apply: lock it in PSOPRDEFN and all psLens access stops immediately
No new database users are created. Nothing connects to the database directly; every query runs through the application server like any other Integration Broker request.
The Whitelist
SWS only answers queries against records listed in PS_C_SWS_REC_WL, scoped to the permission list of the calling API user. A query that references anything off-list is rejected before it reaches the database.
psLens needs roughly 130 PeopleTools metadata records whitelisted. The list is published in two places: the Reference page describes each record and which psLens feature uses it, and Whitelist Tables has the SQL inserts you run during installation. You run those inserts yourself, which means you review every record psLens will ever be able to read, and you can narrow the list at any time.
Integration Broker Setup
The two service operations come with routing definitions and handlers and run on your existing Integration Broker gateway. No new gateway, listening connector, or node is required. Because the traffic is ordinary REST service-operation traffic, it is visible in your IB monitoring tools alongside every other integration.
What to Tell Your DBA
- All queries are reads against PeopleTools metadata tables on the whitelist. SWS has no write path for psLens to call.
- Query volume is driven by on-demand page views plus a configurable alert interval (default every 5 minutes). See the load FAQ for the breakdown.
- There is nothing to install or configure at the database layer. The change is entirely PeopleTools objects plus whitelist rows.
Questions
If your security team needs answers in writing before approving the install (object-by-object review, role configuration, whitelist scoping), raise it on the demo call or email chris.malek@cedarhillsgroup.com.
2 - Code & Supply Chain
What code runs in psLens, how it’s built and distributed, dependency posture, and the vulnerability disclosure & patching process.
This page is for security reviewers who need to understand what is running inside psLens before approving its deployment. It covers four questions:
- What code is actually running?
- Can we audit it?
- How is it built and shipped?
- How are vulnerabilities found, disclosed, and fixed?
If you’re looking for the higher-level read-only / whitelist story, start with Security & Trust and come back here for the detail.
1. What’s Inside the Image
psLens is a single Go binary plus an embedded NATS server, packaged as a multi-stage Docker image distributed from ghcr.io/cedarhillsgroup/pslens. There is no separate database, message broker, or external worker process; one container is the whole application.
Runtime stack
| Component | Purpose |
|---|
| Go 1.26+ | Application language; binary statically linked |
gorilla/mux | HTTP routing |
a-h/templ | Server-rendered HTML templates |
Embedded NATS (nats-server/v2) | In-process key-value store for sessions, alerts, report output |
data-star (datastar.dev) | Hypermedia / SSE for interactive UI; no SPA framework |
| Goldmark | Markdown rendering for report output |
Standard library crypto/aes, crypto/tls | Encryption at rest and in transit |
There is no embedded browser, no third-party telemetry SDK, no analytics tracker. The full dependency list is go.mod in the source tree.
Base image
The runtime stage is debian:bookworm-slim with ca-certificates. No shell access is required for normal operation; psLens runs as PID 1.
2. Source Availability and Review
psLens is closed-source. The source tree is not published publicly.
For customers who need to review the code: Cedar Hills Group offers a read-only source review under NDA as part of the procurement process. Mechanics (on-site, screen-share, time-boxed access) are agreed during contracting. Reach out via the contact page to arrange.
This is the same model used by most enterprise PeopleSoft tooling: the binary is yours to run, the source is reviewable under contract, redistribution is not granted.
3. Build and Distribution
Build pipeline
| Stage | Where it runs | What it produces |
|---|
| Source commit | Cedar Hills Group internal repo | Tagged release commit (semver) |
| CI build | GitHub Actions, GitHub-hosted runners | Multi-arch Docker image |
| Publish | GitHub Container Registry (GHCR) | Private package, tagged vMAJOR.MINOR.PATCH, vMAJOR.MINOR, latest, git SHA |
The release pipeline injects the version, commit SHA, and ISO-8601 build timestamp into the binary at compile time via Go ldflags. You can read them back from any running instance via /healthz and the startup banner in container logs. Useful for confirming exactly which build a customer is running.
What we do today
- Traceable builds. Every image embeds the git SHA and build timestamp in its label and binary; you can map any running container back to the exact source commit that produced it.
- Pinned tag flavors. Production customers pin to
vMAJOR.MINOR (or exact vMAJOR.MINOR.PATCH) so a docker compose pull never surprises them with a major-version change. See Deployment Options for the tag flavors and recommended pinning. - Private package distribution. GHCR access is gated by per-customer read-only fine-grained personal access tokens.
What we don’t do yet (roadmap)
- Image signing with cosign. Planned. Once landed, every published tag will carry a sigstore-verifiable signature and you’ll be able to verify provenance with
cosign verify. - SLSA build provenance attestation. Planned alongside cosign.
4. Dependency Management
Today
go.mod is the single source of truth; all dependencies are pinned by version and content hash (go.sum).- Automated scanning. We run
govulncheck daily and on every push/PR in our GitHub Actions CI pipeline to verify there are no known exploitable vulnerabilities in our dependencies. - Dependency monitoring. Dependabot is enabled to track Go modules, GitHub Actions, and Dockerfile base images, raising automated pull requests for updates.
- The dependency footprint is intentionally narrow (see the table above); Go standard library does most of the work.
If your security policy requires SBOM artifacts as part of vendor onboarding, ask on the demo call. We can generate a CycloneDX or SPDX SBOM from a tagged build on request.
5. Vulnerability Disclosure and Patching
Reporting a vulnerability
Email security@cedarhillsgroup.com. Please include:
- Affected version (the git SHA from
/healthz is most precise) - Reproduction steps or proof-of-concept
- Your assessment of severity (CVSS or descriptive)
We commit to:
- Acknowledgement within 1 business day of receipt.
- Coordinated disclosure. We will agree a disclosure window with the reporter before publishing details.
- Crediting researchers in the release notes unless they prefer otherwise.
Patch SLA
Specific patch targets (business days for Critical, High, Medium) are disclosed during contracting.
When a fix ships, it goes out as a patch release in the same vMAJOR.MINOR stream you’re already pinned to. docker compose pull && docker compose up -d picks it up. Critical fixes are also announced by email to deployment contacts.
Subscribing to release notes
Release notes are published as GitHub Releases on the source repo. Deployment contacts are notified by email for any release with a security note.
6. What Reviewers Usually Ask
“Is the binary statically linked?” Yes. Go produces a static binary; no system library version drift.
“Does it phone home?” No. There is no outbound connection from a running psLens instance other than (a) to your SWS endpoint and (b) to your SMTP server if you’ve enabled magic-link auth. No telemetry, no update checks, no license-server callbacks.
“What user does it run as inside the container?” Confirm the current default with us on the demo call. Recommendation for self-hosters regardless: run with --user 1000:1000 and a read-only root filesystem; only /data needs to be writable.
“How big is the attack surface?” One HTTP listener (default port 8080 or whatever you configure), serving HTML and Server-Sent Events. No raw socket listeners, no UDP, no message-queue ingress, no plugin loader.
3 - Authentication & Access
How users log in to psLens, the deliberate scope decision behind no in-app RBAC, SSO via reverse proxy today, and native SSO on the roadmap.
This page covers how end users authenticate to psLens, what access controls exist (and which deliberately don’t), and how to front psLens with your existing identity provider today.
For SSO, see SSO Today.
1. How Users Log In Today
psLens ships with optional email magic-link authentication. It is off by default in the shipped config.yaml and must be turned on for production deployments.
When auth.enabled: true:
- User visits any psLens URL → redirected to
/login. - User enters their email address.
- psLens emails a one-time verification code to that address (only if the address is on the configured
AuthorizedUsers allowlist). - User enters the code at
/verify-code. - Session created in NATS KV, identified by an HTTP-only
psLens_auth cookie.
| Property | Value |
|---|
| Mechanism | Email one-time code (no passwords) |
| Session storage | NATS KV bucket auth-sessions |
| Session TTL | 1 year (configurable) |
| Cookie | psLens_auth, HTTP-only |
| User allowlist | AuthorizedUsers in config.yaml, case-insensitive |
| Public endpoints (no auth required) | /healthz, /static/*, the auth flow itself |
There are no end-user passwords for psLens to store, leak, hash, or rotate.
Disabling auth entirely is supported only for sandbox or trusted-network deployments. The shipped config defaults to disabled so a first-time installer can get to a working UI quickly. Flip it on before exposing the instance.
2. The Deliberate Scope Decision: No In-App RBAC
psLens has no role-based access control inside the application. Every authenticated user sees the same set of metadata, can run the same reports, and can browse the same PS objects.
This is intentional, not an oversight:
- psLens is read-only. It cannot modify PeopleSoft. The worst an authenticated user can do is read metadata.
- The query surface is whitelisted on the PeopleSoft side by the SWS framework. Even psLens itself cannot query anything off-list. See Security & Trust.
- The access boundary therefore lives at who is on the
AuthorizedUsers list, not at “what role does this user have inside psLens?”. If a user shouldn’t see PS metadata at all, they shouldn’t have a psLens login.
For most customers, the population of people who need psLens (PS developers, sec admins, sys admins, business analysts doing audit work) is small and homogeneous. Adding in-app roles would create configuration overhead without changing the actual blast radius.
If your security policy requires per-user authorization decisions at the application layer, raise it on the demo call. The reverse-proxy patterns below can enforce this without requiring psLens itself to grow an RBAC model.
3. SSO Today: Reverse Proxy
The recommended pattern for any production deployment is to front psLens with a reverse proxy that handles SSO, and turn off the built-in magic-link layer. This delegates authentication to the IdP you already trust.
Common setups:
| Reverse proxy | Identity providers | Notes |
|---|
| Cloudflare Access | Okta, Azure AD, Google Workspace, OIDC, SAML | No infrastructure for you to run; works with the fly.io-managed deployment |
| oauth2-proxy | Google, GitHub, Azure AD, Keycloak, generic OIDC | Self-hosted; sidecar to psLens |
| Pomerium | Any OIDC, SAML | Self-hosted; richer policy engine |
| Tailscale with serve | Any SSO that fronts Tailscale | Network-layer; locks psLens to your tailnet |
Nginx / Traefik / Caddy with forward_auth | Anything that speaks OIDC | Most flexible; you own the wiring |
The pattern is the same in every case:
- The reverse proxy terminates TLS, authenticates the user against your IdP, and only forwards authenticated requests to psLens.
- psLens trusts the proxy (binds to a private network or listens on
127.0.0.1). auth.enabled: false in psLens config. The proxy is the identity boundary.
Cross-link: the TLS termination patterns in Deployment Options cover the same reverse proxies and explain how to wire them up; this page is the identity-layer companion.
What the proxy can do that psLens RBAC could not: enforce group membership (“only the psoft-admins group in Okta”), require MFA, enforce conditional access policies (managed device, geo, time-of-day), and write to your existing IdP audit log.
4. Native SSO on the Roadmap
Native OIDC support inside psLens is planned. No committed date. This will let customers who don’t want a reverse-proxy hop configure their IdP directly in config.yaml.
We are deliberately not promising native SAML. The reverse-proxy patterns above already cover SAML; native OIDC closes the more common gap.
Until native SSO ships, reverse-proxy SSO is production-ready. It is the recommended deployment pattern for every customer with an enterprise IdP.
5. Session Management
| Concern | Behavior |
|---|
| Where sessions live | NATS KV, bucket auth-sessions, scoped to this psLens instance |
| Cookie scope | HTTP-only, marked Secure when served over HTTPS |
| Idle timeout | None today. Sessions live until the TTL expires. |
| Absolute TTL | 1 year (configurable per deployment) |
| Logout | /logout clears the session entry from NATS KV |
| Mass invalidation | Restart the container, or clear the auth-sessions bucket via nats kv. Useful after a credential incident. |
A built-in admin-facing “kill all sessions” UI is on the roadmap. Today the NATS CLI path above is the supported route.
6. What Reviewers Usually Ask
“Can we require MFA?” Yes, by fronting with a reverse proxy that enforces MFA at the IdP layer (any of the proxies above). Magic-link auth on its own is single-factor (control of the email inbox).
“Where does the user email come from on the SWS side?” psLens authenticates its own users via magic-link or reverse-proxy SSO. Those are the people using the psLens UI. psLens authenticates to PeopleSoft via the SWS service account (basic auth, see Code & Supply Chain). The two identity domains are independent. Your psLens users do not need PS accounts.
“Can we revoke a user instantly?” Yes. Remove them from AuthorizedUsers and restart; their next request fails. With reverse-proxy SSO, revoke them at the IdP and they lose access on the next request, no restart needed.
“Does psLens store passwords?” No end-user passwords. The only password-shaped secret psLens holds is the SWS service-account password used to call PeopleSoft, encrypted at rest with AES-256-GCM. See Data Handling & Logging.
4 - Data Handling & Logging
What psLens stores, what it does not, how data is encrypted at rest and in transit, and what gets logged for audit.
This page is for compliance reviewers and DPOs who need a precise answer to “what data does psLens hold, where, and for how long?”, and for security teams checking encryption and audit-trail posture.
For PII handling, jump to Personal Data (PII).
1. What psLens Stores
psLens persists three categories of data, all inside the customer’s own dedicated instance. There is no shared multi-tenant backend.
| Where | What | Retention | Notes |
|---|
/data/nats (NATS JetStream KV) | Alert history | Rolling window (configurable; short by default) | Alerts are about current problems. History is for trend review, not long-term audit. |
/data/nats | Report output (Markdown) | 90 days | So you can revisit past audit findings; configurable |
/data/nats | Recently-viewed objects per user | Session-scoped | Navigation convenience; not an audit log |
/data/nats | Encrypted DB / SWS credentials | Until deleted | AES-256-GCM, key from PSLENS_MASTER_KEY env var |
/data/nats | Auth sessions (if auth.enabled) | Up to 1 year TTL | See Authentication & Access |
/data/projects | Uploaded PS project archives (.zip) | Until deleted | Used by Project Compare; you control the upload set |
/app/config.yaml | Configuration (DB names, SWS endpoints, optional credentials) | Until you change it | Bind-mounted from your filesystem; secrets preferably via env vars |
That is the complete persistent footprint. Everything else (query results, page renders, search hits) is generated on demand and not written to disk.
2. What psLens Does NOT Store
- PeopleSoft business data. Employee records, payroll, financial transactions, HR data, customer records, journals, vouchers. None of it. Reports summarize at runtime and discard the raw rows.
- Database passwords in cleartext (when
PSLENS_MASTER_KEY is set). - End-user passwords. psLens uses magic-link or reverse-proxy SSO; there are no user passwords to store.
- Logs on disk. Logs go to stderr; your container runtime decides what to do with them.
- Telemetry, analytics, or usage data shipped back to Cedar Hills Group. psLens does not phone home.
- Client-side cached data. Nothing is cached in the browser. No writes to
LocalStorage, SessionStorage, or IndexedDB; close the tab and there is nothing left.
3. Personal Data (PII)
The answer is more nuanced than “no PII”.
psLens does not store PeopleSoft user PII. No persistent table or KV entry contains employee or operator records.
psLens does process PeopleSoft user PII at request time. When a user opens a search for Users, Operator IDs, or related security objects, psLens queries PeopleSoft, renders fields like OPRID, OPRDEFNDESC, EMAILID, and EMPLID in the browser, and discards the rows after the response. The data passes through psLens memory; it is not written to NATS, disk, or any log.
What this means for GDPR / CCPA / similar:
- psLens acts as a processor of this data while a query is in flight.
- The controller is the PeopleSoft owner (the customer).
- A DPA is available on request. See Compliance & Vendor.
- Subject access / erasure requests are handled at the PeopleSoft source of record. psLens has nothing to delete because it has nothing persisted.
If your jurisdiction or policy requires that even transient processing be scoped, the AuthorizedUsers allowlist and the SWS table whitelist give you two layers of control over who can trigger such a query at all.
4. Encryption
In transit
| Hop | Protocol | Notes |
|---|
| Browser → psLens UI | HTTPS | Via your TLS pattern. See Deployment Options (6 options compared). |
| psLens → SWS endpoint | HTTPS | Basic-auth credentials never on the wire in clear |
| psLens → SMTP (if magic-link auth) | SMTPS / STARTTLS | Configurable per your SMTP provider |
The SWS endpoint URL is HTTPS in every supported deployment. If you have a network where the PS server is reachable only over HTTP, raise it on the demo call. Running psLens over plaintext to PS is not a supported posture.
At rest
| Item | Encryption | Key source |
|---|
| SWS / DB credentials in NATS KV | AES-256-GCM | PSLENS_MASTER_KEY env var (32 bytes, hex-encoded) |
| Auth sessions in NATS KV | Opaque session IDs only; no secret material at rest | n/a |
| Report output | Not encrypted (plain Markdown) | Stored on the customer-controlled volume |
| Alert history | Not encrypted (alert metadata) | Stored on the customer-controlled volume |
| Project archive uploads | Not encrypted at application layer | Disk-level encryption (LUKS, fly.io volumes, EBS) is the recommended boundary |
Master key management:
- Required (and enforced at startup) when
PSLENS_ENV=production. - Stored as a 64-char hex string (32 raw bytes) in the
PSLENS_MASTER_KEY env var. On fly.io: fly secrets set PSLENS_MASTER_KEY=.... In Docker Compose: .env file with 0600 permissions, or an external secret manager. - Back it up out of band. Losing the master key means encrypted DB credentials in NATS KV become unreadable; you’d need to re-enter them.
- Self-service rotation. Generate a new key and trigger rotation directly from the Settings UI (Advanced page). The server decrypts all stored credentials using the old key and re-encrypts them with the new key in NATS KV. The operator must update the
PSLENS_MASTER_KEY environment variable in the deployment configuration to match the new key before the container restarts.
5. Audit Logging
What psLens logs today
| Event | Where it goes | Includes |
|---|
| Every HTTP request | stderr (structured slog) | X-Request-Id, path, method, status, duration, authenticated user email (if auth.enabled) |
| Application errors | stderr (structured slog) | Stack-relevant context, request ID for correlation |
| Startup banner | stderr | Version, commit SHA, build timestamp |
| Alert checker runs | stderr + NATS KV (alert history) | Which checker, what it found |
The request ID flows through every log line tied to a request, so you can correlate a UI action to its server-side handler chain.
Logs are written to stderr only. psLens does not write logs to disk. Your container runtime decides what happens next: typically piped to your Docker logging driver, your systemd journal, your fly.io log stream, or your K8s log shipper. Send them to your SIEM via the same standard mechanism you use for any container workload.
Where the user-action audit actually lives today
Because psLens is read-only, the question “who looked at what PS data, when” has its authoritative answer on the PeopleSoft side. The SWS framework logs every query it accepts, including the OPRID of the SWS service account, the SQL it ran, and the timestamp. That is the audit trail that matters for “did someone see employee X’s record”.
What psLens contributes:
- The HTTP request log (above) ties an authenticated psLens user to a specific page hit, and the page hit corresponds to a known set of SWS queries.
- Correlation across the two logs uses the request ID on the psLens side and the timestamp + query pattern on the SWS side.
The gap and the roadmap
Today, psLens does not write a structured per-user “action” audit log. For example, {user: alice, action: viewed, object: PSRECDEFN PS_VOUCHER, at: 2026-05-21T14:32Z}. The HTTP request log is close to that but is operational logging, not an audit artifact.
Roadmap: add a first-class user-action audit log written to a NATS KV bucket with configurable retention, exportable to your SIEM. Targeted to land alongside native SSO. No committed date.
If a customer needs a richer audit story today, the recommended interim is: enable auth.enabled, ship the HTTP request log to your SIEM, and correlate with the SWS-side audit. Cedar Hills Group can help with the correlation queries.
Retention
psLens retains structured logs only in your container runtime’s log stream. Retention is whatever you configure there. No psLens-managed log retention policy exists; we deliberately stay out of that decision so it aligns with your existing log-retention SLAs.
6. What Reviewers Usually Ask
“Where is the data physically?” In your dedicated psLens instance. Managed deployments live in the fly.io region you choose at provisioning. Self-hosted: wherever you run the container. There is no shared backend.
“Can you delete all data for a customer on request?” Yes, by removing the deployment. Because all customer-specific state lives in the per-customer container’s /data volume, deletion is fly apps destroy or docker compose down --volumes. There is no other location to scrub.
“Do you encrypt the entire volume?” Application-level encryption covers credentials. Volume-level encryption is the customer’s choice. On fly.io, volumes are encrypted at rest by default; on your own infrastructure, use LUKS / EBS encryption / equivalent.
“Do you have an SBOM?” Available on request for any tagged build. See Code & Supply Chain.
5 - Deployment & Operations
How psLens is deployed, network requirements, sizing, backup, upgrade, DR, monitoring — consolidated for ops and security reviewers.
This page consolidates the operational story that an IT or DBA reviewer needs in one place. It overlaps with Installation and Deployment Options; those are the how-to references, and this page is the what-to-expect security-review companion.
1. Deployment Model
- One container per customer. Each customer gets a dedicated psLens deployment: separate process, separate NATS instance, separate
/data volume. - No shared multi-tenant backend. There is no Cedar Hills Group SaaS plane that customer instances talk to. Your psLens instance talks to your PeopleSoft and (optionally) your SMTP, and that is it.
- Two hosting options:
| Mode | Operated by | Where it runs |
|---|
| Managed | Cedar Hills Group | fly.io, in the region you choose at provisioning |
| Self-hosted | You | Docker, docker-compose, Kubernetes, or systemd on a Linux VM. Your cloud, on-prem, or air-gapped. |
The choice is reversible. You can start managed and migrate to self-hosted (or vice versa). The data volume is portable and the configuration travels.
2. Network Requirements
Inbound
| From | To | Why |
|---|
| Your users (browsers) | psLens UI on HTTPS (port per your TLS pattern) | The whole point |
| Your monitoring system | GET /healthz | Liveness check, returns 200 OK |
Outbound
| From | To | When |
|---|
| psLens | Your SWS endpoint (HTTPS) | Every request that hits PeopleSoft |
| psLens | Your SMTP server | Only if auth.enabled: true and you’re using built-in magic-link |
| psLens | Anywhere else | Never. No telemetry, no update checks, no callback to Cedar Hills Group. |
This means psLens runs cleanly behind strict egress filtering. Allow it the SWS hostname (and SMTP host if applicable) and deny everything else.
TLS termination
Cross-link: Deployment Options → TLS compares 6 patterns (native cert, Let’s Encrypt, Caddy, nginx, Traefik, Tailscale Serve). Pick the one that matches your existing edge.
3. Sizing
Recommended minimums:
| Resource | Minimum | Notes |
|---|
| CPU | 1 vCPU | Matches the smallest fly.io machine class currently in production |
| RAM | 512 MB | Most requests are well under this; reports can spike briefly |
| Disk | 1 GB persistent | NATS KV + uploaded project archives; grow if you upload many projects |
| Network | ~negligible | Metadata queries are small; most traffic is HTML rendering |
For deployments handling many concurrent users or running heavy reports, scale up to 2 vCPU / 1 GB RAM. psLens is a single Go process; vertical scaling is the path, and there is no clustering model today.
4. Backup and Restore
What to back up
| Path | Contents | Loss impact |
|---|
/data/nats | Alert history, report output, encrypted credentials, sessions, recently-viewed | Lose alert/report history; users re-enter PS DB passwords |
/data/projects | Uploaded PS project archives | Re-upload from source |
/app/config.yaml | Configuration | Re-create from your config-management tooling |
PSLENS_MASTER_KEY (env var) | Encryption key for credentials in /data/nats | Without it, the encrypted credentials in NATS KV are unreadable. Back up out of band (password manager, vault, secret store). |
Suggested cadence
- Nightly tarball of
/data/nats and /data/projects to your backup target. - 14–30 day retention for daily snapshots; longer if your audit policy requires.
- Master key stored separately (so a single-system compromise can’t yield both).
Example backup script (Docker host):
#!/usr/bin/env bash
set -euo pipefail
TS=$(date -u +%Y%m%dT%H%M%SZ)
docker run --rm \
--volumes-from pslens \
-v "$BACKUP_DIR":/backup \
alpine \
tar czf "/backup/pslens-${TS}.tar.gz" /data
Restore
- Stop the container.
- Restore the tarball into a fresh
/data volume. - Ensure
PSLENS_MASTER_KEY matches the key that encrypted the credentials. - Start the container.
5. Disaster Recovery
Today’s posture:
- For self-hosted: DR is whatever your existing container DR posture is. psLens fits the same pattern as any small stateful Go service: restore the data volume, restart.
- For managed (fly.io): redeployment is fast because all state fits in one volume. Cedar Hills Group operates the deployment; RTO/RPO targets for managed deployments are disclosed during contracting.
- No multi-region replication of psLens state today. The single-customer scope makes this rarely worth the complexity, but if your contract requires it, raise it on the demo call.
If you need a higher DR posture than this, the answer is usually “self-host and use your existing DR tooling for the volume.” Cedar Hills Group can help structure that.
6. Monitoring
What ships today
GET /healthz returns 200 OK if the process is alive. Liveness check only; no readiness signal beyond startup completion.- Structured slog to stderr for every request and every error. Ship to your SIEM via your container runtime’s log driver.
- Startup banner in logs: version, commit SHA, build timestamp. Useful for confirming an upgrade landed.
- Connection-status UI inside psLens shows live SWS reachability for each configured database.
What doesn’t ship today
- No Prometheus
/metrics endpoint. Planned. No committed date. - No built-in alerting, in the sense of “psLens noticing it has a problem and notifying you.” That is your monitoring system’s job, fed by
/healthz and the log stream.
Recommended wiring for a customer environment:
| Signal | How to monitor |
|---|
| Process alive | GET /healthz from your uptime monitor every 30–60 s |
| Errors | Forward stderr to your log aggregation; alert on error-rate spikes |
| Auth failures | Same: the request log includes status codes |
| SWS reachability | psLens already shows this; if you want it externalized, build a small probe against /healthz |
7. Upgrades and Rollback
Pin production to a vMAJOR.MINOR tag. To upgrade:
docker compose pull
docker compose up -d
The data volume survives the restart. Schema migrations on the NATS KV layer (if any) run automatically on first start of the new version.
To roll back, pin to the prior vMAJOR.MINOR.PATCH tag, docker compose up -d. Downgrade compatibility within a vMAJOR.MINOR is guaranteed; across major versions, check the release notes.
Breaking change contract: breaking changes only land in major version bumps and are called out explicitly in release notes. Patch and minor releases preserve config compatibility.
Cross-link: Deployment Options → Image Tags for the full tag-flavor table.
8. Multi-Environment Support (DEV / TEST / PROD)
A single psLens instance can be configured to connect to multiple PeopleSoft databases (DEV, TEST, PROD, demo) via entries in config.yaml. The database selector appears on every search and report page.
This is usually the right deployment shape: one psLens instance per psLens user community, configured to see every PS environment that community needs. It is rarely useful to run multiple psLens instances unless those communities have non-overlapping access requirements that need to be enforced at the network layer.
9. DBA Concerns: What psLens Does to Your PS Server
For PeopleSoft admins who need to sign off on the load profile:
| Property | Behavior |
|---|
| Connection type | HTTPS to SWS, basic auth, no JDBC, no direct DB connection |
| Read or write | Read-only. No code path issues INSERT, UPDATE, or DELETE. |
| Table coverage | Only whitelisted PeopleTools metadata tables (PSRECDEFN, PSPNLDEFN, PSAUTHITEM, process scheduler, IB tables, etc.) |
| Query shape | Mostly short metadata reads. Reports use a 90-second QuerySlow path; nothing runs longer. |
| Concurrency | One concurrent request per active user; small (handful) at any moment for typical customers |
| Service account permissions | Read on whitelisted tables; no write, no execute |
The PS-side audit trail (SWS query log) captures every query psLens issues with timestamps and the SWS service-account OPRID. If psLens is misbehaving, that log shows what it actually did.
Cross-link: Installation → Whitelisting Tables for the full list and SQL.
6 - Compliance & Vendor
SOC 2 posture, GDPR / personal-data handling, DPA, sub-processors, business continuity, and how psLens fits in a vendor-risk review.
This page is for procurement, legal, and vendor-risk reviewers. It states current posture plainly, including where certifications do not yet exist.
If you’re filling out a vendor questionnaire (SIG, CAIQ, custom), the Security Questionnaires section is the right place to start.
1. SOC 2 — Current Posture
Cedar Hills Group is not SOC 2 certified today. Certification is on the roadmap. No committed date.
In the interim, this site documents the controls a SOC 2 Type II report would cover, so a reviewer can map them to their own framework. The relevant Trust Service Criteria and where they’re addressed:
This map is not a SOC 2 report; it is a vendor-side description of controls. We will fill out your SIG, CAIQ, or in-house questionnaire and return it (see below).
2. GDPR and Personal Data
- psLens does not persist PeopleSoft user PII. There is no stored copy of employee, operator, or HR records.
- psLens does process PeopleSoft user PII at request time when users search Users / OPRIDs / EMPLIDs. Data is rendered to the browser and discarded.
- For GDPR purposes, the customer (the PeopleSoft owner) is the controller; psLens / Cedar Hills Group is the processor.
What this means in practice:
| Topic | psLens posture |
|---|
| Data Processing Agreement (DPA) | Available on request as part of the contract |
| Sub-processors | See Sub-Processors below |
| International data transfers | Self-hosted: you choose. Managed: you choose the fly.io region at provisioning. |
| Data subject access requests | Source data is in PeopleSoft; the customer handles requests at the source of record. psLens has nothing persisted to deliver or delete. |
| Right to erasure | Same. psLens stores no PS user PII to erase. |
| Audit / records of processing | Request-level logging is in your container runtime; SWS-side query log on the PS side. See Data Handling & Logging → Audit Logging. |
For CCPA, the answer mirrors GDPR: psLens does not “sell” data, does not retain data, and processes only at request time.
3. Data Residency
| Deployment | Where data lives |
|---|
| Managed on fly.io | The fly.io region you choose at provisioning. Cedar Hills Group does not move data between regions. |
| Self-hosted | Wherever you run the container: your cloud, your on-prem, or your air-gapped network |
| Air-gapped | Fully supported. psLens does not require outbound internet at runtime beyond reaching your SWS endpoint. |
There is no shared multi-tenant backend, so there is no place for data to “leak” into a different region by accident.
4. Sub-Processors
The sub-processor list depends on the deployment mode you choose:
| Deployment | Sub-processor | Why |
|---|
| Managed (any) | fly.io | Application hosting |
| Managed or self-hosted with magic-link auth | Your chosen SMTP provider (or Cedar Hills Group’s, if not specified) | Delivering one-time auth codes |
| All | GitHub (GHCR) | Image distribution; only at docker pull time, not at runtime |
Self-hosters who don’t use magic-link auth have no Cedar Hills Group sub-processors at runtime. You run the infrastructure end to end.
The specific SMTP provider used by default for managed deployments is named during contracting so it can be reviewed against your vendor list.
Notification of sub-processor changes is provided in the DPA and in writing to deployment contacts.
5. Contract, SLA, and Termination
| Topic | Posture |
|---|
| Contract length | Negotiated per customer; typical terms discussed on the demo call |
| SLA (managed) | Uptime targets and support response targets are disclosed during contracting |
| Support | Setup assistance included; ongoing support terms in the agreement |
| Termination & data return | All customer state lives in the per-customer /data volume. On termination, you can take a final tarball before the instance is destroyed. Self-hosters keep everything by definition. |
| Pricing | $500/month subscription + one-time setup fee ($2,500 managed / $4,500 self-hosted). Excludes multi-client hosting providers. |
| Liability and insurance | Commercial general liability and cyber policy details available on request during contracting |
6. About Cedar Hills Group
Cedar Hills Group is a PeopleSoft consultancy. The same team that built the SWS framework (the bounded REST API that psLens uses to talk to PeopleSoft) builds psLens, so the access path psLens uses is one we control end to end.
What this means for vendor reviewers:
- The team has run real PS environments for real customers and built psLens out of that operational need.
- Cedar Hills Group is reachable and contactable; this is not a self-service SaaS where you can’t get a human on a call. See contact.
More on the company: cedarhillsgroup.com.
7. Business Continuity: What Happens If Cedar Hills Group Goes Away
A fair question in any vendor review:
- You keep the Docker image you’re running. GHCR can rotate tokens or change ownership; the image you’ve already pulled keeps working. Pin to a specific
vMAJOR.MINOR.PATCH and you have an indefinite-life binary. - Self-hosting works without Cedar Hills Group infrastructure. No runtime callback, no license check, no cloud control plane. If our domain disappeared tomorrow, every self-hosted instance keeps running.
- Managed deployments could be migrated to self-hosted. All state is in the per-customer
/data volume. Cedar Hills Group commits to providing the volume and configuration on termination so you can restart it on your own infrastructure. - Source escrow. Available on request for enterprise contracts.
Together: a binary you already hold, a portable data volume, and (on enterprise contracts) source escrow. That is the answer to “what is our exposure if the vendor goes away.”
8. Security Questionnaires
We complete the following questionnaires on request as part of an evaluation:
- SIG Lite. Standard short form.
- SIG Core. Long form.
- CAIQ (Cloud Security Alliance). For cloud-shape reviews.
- Your own custom questionnaire. Preferred, since it asks what your team actually cares about.
To kick this off, email chris.malek@cedarhillsgroup.com with the questionnaire attached, or raise it on the demo call.
For questions that are common across questionnaires, the answer often already lives in one of the pages below. Cross-referencing those pages in your questionnaire response is encouraged.