Source code
Revision control
Copy as Markdown
Other Tools
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/**
* Sticky security-flag container. A flag that has been set to `true` can never
* be cleared back to `false`, preventing a later tool call from accidentally
* downgrading a flag raised by an earlier one.
*
* Flags are written to a staging area and only become visible after `commit()`
* is called. This ensures that parallel tool calls requested in the same
* conversation turn all see the same committed flags.
*/
export class SecurityProperties {
#privateData = false;
#untrustedInput = false;
#newPrivateData = false;
#newUntrustedInput = false;
/** @returns {boolean} */
get privateData() {
return this.#privateData;
}
setPrivateData() {
this.#newPrivateData = true;
}
/** @returns {boolean} */
get untrustedInput() {
return this.#untrustedInput;
}
setUntrustedInput() {
this.#newUntrustedInput = true;
}
/**
* Promotes staged flag values to the committed state. Call this once all
* tool calls in a batch have completed so that parallel tool calls all see
* the same flags.
*/
commit() {
this.#privateData = this.#privateData || this.#newPrivateData;
this.#untrustedInput = this.#untrustedInput || this.#newUntrustedInput;
this.#newPrivateData = false;
this.#newUntrustedInput = false;
}
/**
* Serializes committed flag state for persistence. Staged flags are
* runtime coordination state and are not included.
*
* @returns {{ privateData: boolean, untrustedInput: boolean }}
*/
toJSON() {
return {
privateData: this.#privateData,
untrustedInput: this.#untrustedInput,
};
}
/**
* Restores a SecurityProperties instance from a persisted JSON object.
* Returns a clean default instance if input is null or undefined.
*
* Migration behavior: Conversations created before securityProperties
* persistence existed have no stored flag payload. Those conversations
* restore as false/false and will only become tainted again if later
* conversation activity sets and commits the flags.
*
* @param {object|null} obj - Parsed JSON from SQLite
* @returns {SecurityProperties}
*/
static fromJSON(obj) {
const props = new SecurityProperties();
if (!obj) {
return props;
}
if (obj.privateData) {
props.#privateData = true;
}
if (obj.untrustedInput) {
props.#untrustedInput = true;
}
return props;
}
/**
* Get text that can be used in logging.
*
* @returns {string}
*/
getLogText() {
return `private=${this.privateData} untrusted=${this.untrustedInput}`;
}
}