Skip to content

Read-only access

AI Assist only reads. That promise doesn’t depend on the LLM behaving well, or even on the server being free of bugs: the database enforces it. This page explains the controls, from the database account up, and what each one guarantees.

The server connects with a dedicated account, such as AIPS_MCP, that has read access to the 28 PeopleTools tables its tools need, plus any application tables you allow for run_select, and nothing else. So:

  • Nothing can write. No tool, prompt, or bug can insert, update, or delete a row, or change a definition, because the account has no privilege to do so. The database refuses.
  • Nothing else can be read. A query against any other table fails in the database, whatever the server’s own checks decide.
  • Every other control is extra. The server’s checks give the LLM clear errors and stop most mistakes early, but your data doesn’t depend on them.

Create the database account has the scripts, and the queries that prove what the account can do.

On Oracle Database, the grant scripts use the READ object privilege rather than SELECT. Both allow queries, but SELECT also allows an account to lock rows, with SELECT … FOR UPDATE, and to lock whole tables, with LOCK TABLE. A locked row blocks every PeopleSoft process that needs to update it. READ, available since Oracle Database 12c (12.1.0.2), allows queries and nothing more.

On SQL Server, the account has SELECT. A query with a locking hint, such as WITH (UPDLOCK), could hold locks while it runs, so run_select rejects locking hints, and the server’s own queries never use them.

Every tool except run_select runs SQL that’s written in advance and stored in the server. Tool arguments only ever become bind variables:

The record header, as describe_record reads it (Oracle Database)
SELECT RECNAME, RECTYPE, SQLTABLENAME, RECDESCR,
RELLANGRECNAME, AUDITRECNAME,
LASTUPDDTTM, LASTUPDOPRID
FROM PSRECDEFN
WHERE RECNAME = :record

Before a value is bound, the server checks it against the tool’s input schema and PeopleSoft’s naming rules. A record name, for example, must be 1 to 15 letters, digits, and underscores, starting with a letter. There’s no way for an argument to become part of the SQL itself, so the classic SQL injection attack, where input changes what a query does, can’t happen.

run_select is different: the LLM writes the SQL. Before it runs, the server parses the query and checks that it’s a single SELECT, that it doesn’t lock anything, that every table it reads is on the allow-list, and that sensitive columns are only selected, so they can be masked. The run_select reference lists the rules.

Those checks exist to give the LLM precise errors it can learn from. The protection comes from the account: even a query that got past the checks couldn’t read a table the account wasn’t granted, or change anything. run_select is also off until an administrator turns it on, as Protecting data explains.

PeopleSoft’s own users come first. These limits keep AI Assist from slowing them down:

Limit Default What it prevents
READ grants on Oracle Always Locked rows and tables
Query timeout 30 seconds Long-running queries, which are cancelled
Row caps Per tool, such as 1,000 rows for run_select Large result sets
Connection pool 4 connections More than a few sessions at once, whatever the number of users
Rate limit 60 calls per minute per person One person, or a runaway agent, flooding the server
Output limits 2,000 lines of PeopleCode per call A single result overwhelming the LLM

Your database administrator can also cap the account in the database itself, for example with an Oracle Database profile that limits its sessions, as shown in Create the database account.

Suppose an attacker took over the server, or stole its database password. They would have exactly what the account has:

  • They could read the PeopleTools tables on the list, which means your definitions and all your PeopleCode and SQL, and the application tables allowed for run_select.
  • They couldn’t change anything, lock anything on Oracle Database, or read any other table, including PSOPRDEFN and PSACCESSPRFL.

To keep that from happening, protect the password as the setup pages show, in a Podman secret or a file only the service can read, and change it if you suspect it has leaked. A shared server keeps the password off developers’ machines altogether.