Welcome to the final chapter of our tutorial series!
In the previous chapter, Graceful Exit Management, we learned how to safely shut down the application if the user refuses to trust a workspace.
But imagine you are the developer of this tool. You have thousands of users. You might wonder:
To answer these questions, we need Trust Analytics & Auditing.
Think of an airplane. It has a "Black Box" flight recorder. It doesn't fly the plane, but it records exactly what is happening: "Altitude: 30,000ft," "Engine: On," "Landing Gear: Down."
In TrustDialog, our analytics system serves as the Black Box for security decisions.
It records two critical moments:
By recording the Security Context (what made the folder risky) during these moments, we can audit the safety of our ecosystem.
We log specific events to our analytics server using a helper function called logEvent.
tengu_trust_dialog_shownThis event fires the moment the Trust Dialog appears on the screen. It tells us: "We just warned a user."
tengu_trust_dialog_acceptThis event fires only if the user explicitly selects "Yes, I trust this folder." It tells us: "The user overrode the warning."
(Note: We don't explicitly log "exit" because the application shuts down immediately, but we can infer it if we see a "shown" event without a matching "accept" event.)
logEvent FunctionThe interface for logging is very simple. You provide the event name and a "payload" object containing the facts.
import { logEvent } from 'src/services/analytics/index.js';
// Example: Logging that we showed the dialog
logEvent("tengu_trust_dialog_shown", {
isHomeDir: true, // Was it the home directory?
hasBashExecution: true, // Did we find Bash scripts?
hasMcpServers: false // Were there config servers?
});
Explanation:
TrustDialog.tsxLet's see where these loggers fit into the main React component. We need to capture the data at two specific points in the lifecycle.
Before we log anything, we collect all the risk factors (as we learned in Chapter 2).
// Inside TrustDialog function
const { servers } = getMcpConfigsByScope('project');
const hasMcpServers = Object.keys(servers).length > 0;
const bashSources = getBashPermissionSources();
// We combine different bash checks
const hasAnyBashExecution = bashSources.length > 0 || hasSlashCommandBash;
Explanation:
These boolean variables (true/false) create the "fingerprint" of the risk.
We want to log that the dialog appeared exactly once, right when the component loads. In React, we use useEffect for this.
React.useEffect(() => {
const isHomeDir = homedir() === getCwd();
// Log that the user is seeing the warning
logEvent("tengu_trust_dialog_shown", {
isHomeDir,
hasMcpServers,
hasBashExecution: hasAnyBashExecution,
hasDangerousEnvVars
});
}, []); // Empty array means "Run once on mount"
Explanation:
useEffect: This runs the moment the Trust Dialog is rendered to the terminal.If the user selects "Yes", we log the second event right before we close the dialog.
const onChange = (value) => {
if (value === "exit") {
gracefulShutdownSync(1); // No log needed, just exit
return;
}
// User clicked "Yes"
logEvent("tengu_trust_dialog_accept", {
isHomeDir: homedir() === getCwd(),
hasMcpServers,
hasBashExecution: hasAnyBashExecution,
// ... pass other flags
});
onDone(); // Proceed to app
};
Explanation:
We place the log call inside the else block (where the user did not exit). This confirms that they actively chose to proceed despite the risks.
Here is how the data moves from the user's terminal to the analytics system.
logEvent
While TrustDialog calls the function, where does logEvent actually go? It usually lives in a service file like src/services/analytics/index.js.
The implementation is designed to be non-blocking. We don't want the user to wait for a network request to finish before the app starts.
// src/services/analytics/index.js (Simplified Concept)
export function logEvent(eventName, properties) {
// 1. Add timestamp and session ID
const payload = {
event: eventName,
timestamp: Date.now(),
properties: properties
};
// 2. Send to server "fire and forget"
// We don't await this promise because we don't want to block the UI
fetch('https://analytics.example.com/api', {
method: 'POST',
body: JSON.stringify(payload)
}).catch(err => {
// If analytics fail, we don't crash the app.
// We just ignore the error silently.
});
}
Key Takeaway:
Note the .catch() block. Logging is important for us, but it is optional for the user. If the user is offline, the app should still work perfectly. We never let a failed log crash the program.
Congratulations! You have completed the TrustDialog tutorial series.
Let's recap the journey we took to build a secure, user-friendly Trust System:
By combining these five concepts, you have created a robust security barrier that respects the user's workflow while keeping their computer safe.
Project Complete.
Generated by Code IQ