AI Engineer World's Fair 2026

SonarQube + OpenAI: Agentic Development — Killian Carlsen-Phelan, Sonar

Slide chapters

31 slide and demo groups · Timestamps are approximate. 1 additional group was omitted from this pass.

Workshop resources

Scan the QR code or visit the workshop repository to follow along. Killian notes that there are a few prerequisites.

Text in image
https://github.com/sonar-samples/learn-codex-workshop

Sonar

Wiring Your Team for Agentic Development

Killian Carlsen-Phelan introduces the session with a question: how can teams verify that code and other output generated by agents like Codex are safe?

Text in image
Wiring Your Team for Agentic Development with SonarQube & OpenAI

Killian Carlsen-Phelan | Developer Content Engineer

Sonar

Agent Centric Development Cycle

Sonar introduces a cycle around agent-generated code. Carlsen-Phelan frames verification as the new bottleneck as agents generate more code.

Text in image
Introducing the
Agent Centric Development Cycle

The Sonar methodology for ensuring AI agents are operating in a trustworthy, consistent, and transparent way.

Agent Centric Development Cycle
GUIDE
VERIFY
SOLVE
GENERATE
AC/DC
Sonar

The three key stages of the AC/DC

Guide supplies context and constraints; Verify checks generated code; Solve fixes issues and feeds lessons back into Guide. The diagram places these stages in a loop around Generate.

Text in image
The three key stages of the AC/DC

Guide
DEFINE CONTEXT AND CONSTRAINTS
Provide agents with guardrails and the most relevant context, standards, and architectural constraints so output fits the organization’s requirements.

Guide
Generate
Solve
Verify

Verify
REVIEW AND VALIDATE CODE
Mandatory multi-layer verification with deterministic evaluation, logical AI reasoning, and runtime validation in a sandbox to ensure quality, security, compliance, and functionality.

Solve
FIX ISSUES
Automated debugging and remediation based on verification feedback. Issues are fixed, and lessons feed back into the Guide phase.

Confidential - ©2026, SonarSource Sàrl
4

The inner loop and the outer loop

The inner loop guides, verifies and fixes code during agent reasoning in the IDE. The outer loop runs broader checks after the agent finishes, as in a CI pipeline that can send developers back to fix failures.

Text in image
The inner loop and the outer loop

The inner loop:
Guide-Verify-Solve happens in each agentic reasoning loop, ensuring that the agent stays on track as it methodically works to achieve the plans.

Guide
Generate
Solve
Verify

The outer loop:
Guide-Verify-Solve happens once the agent has ‘finished’ its work. Here, more comprehensive verification occurs and, often, the agent will have to fix larger-scale issues that are identified.

Confidential - ©2026, SonarSource Sàrl
5

SonarQube Cloud setup

Carlsen-Phelan runs his personal Apply Sonar script, then authorizes the connection in a browser. The success page says the token was sent to the terminal to finish setup.

Text in image
Connection successful!

Your user token has now been generated & sent to your terminal.

Return to your terminal to complete the setup.

Interface text:
SonarQube Cloud
Authorize SonarQube CLI?
sonarcloud.io/auth?product=cli&port=64124

13:34Demo milestone · Completed build

Show 2 builds
  1. 12:08

    Code editor showing Python database functions and a terminal running a Sonar setup script.

    Text in image
    def search_tasks(query):
        """Search tasks by title."""
        conn = sqlite3.connect(DATABASE_PATH)
        cursor = conn.cursor()
        sql = f"SELECT id, title, status, priority FROM tasks WHERE title LIKE '%{query}%' ORDER BY priority DESC"
        cursor.execute(sql)
        results = cursor.fetchall()
        conn.close()
        return results
    
    def export_tasks(status_filter):
        """Export filtered tasks to a CSV file."""
        filename = tempfile.mktemp(suffix=".csv")
    
        conn = sqlite3.connect(DATABASE_PATH)
        cursor = conn.cursor()
        cursor.execute("SELECT * FROM tasks WHERE status = ?", (status_filter,))
        tasks = cursor.fetchall()
    
    Terminal:
    dryrun-1 on main via v3.9.6
    ./apply-sonar.sh
    
    Interface text:
    EXPLORER
    DRYRUN-1
    .claude
    .gitignore
    app.py
    apply-sonar.sh
    config.py
    database.py
    README.md
    tasks.py
    PROBLEMS 1
    OUTPUT
    DEBUG CONSOLE
    TERMINAL
    PORTS
    SONARQUBE 1
    PIXEL AGENTS
    OUTLINE
    TIMELINE
  2. 13:34

    Browser confirms that the connection succeeded and directs the user back to the terminal.

    Text in image
    Connection successful!
    
    Your user token has now been generated & sent to your terminal.
    
    Return to your terminal to complete the setup.
    
    Interface text:
    SonarQube Cloud
    Authorize SonarQube CLI?
    sonarcloud.io/auth?product=cli&port=64124

Select an organization

After SonarQube Cloud returns a token, the terminal asks which organization to use. The presenter says to choose the organization created with the account.

Text in image
def search_tasks(query):
    """Search tasks by title."""
    conn = sqlite3.connect(DATABASE_PATH)
    cursor = conn.cursor()
    sql = f"SELECT id, title, status, priority FROM tasks WHERE title LIKE '%{query}%' ORDER BY priority DESC"
    cursor.execute(sql)
    results = cursor.fetchall()
    conn.close()
    return results

def export_tasks(status_filter):
    """Export filtered tasks to a CSV file."""
    filename = tempfile.mktemp(suffix=".csv")

    conn = sqlite3.connect(DATABASE_PATH)
    cursor = conn.cursor()
    cursor.execute("SELECT * FROM tasks WHERE status = ?", (status_filter,))
    tasks = cursor.fetchall()

Terminal:
./apply-sonar.sh
Where would you like to connect? SonarQube Cloud
Which SonarQube Cloud region? EU (sonarcloud.io)
Authenticating with: https://sonarcloud.io
Obtaining access token from SonarQube...
URL: https://sonarcloud.io/auth?product=cli&port=64124
Press Enter to open the browser
Waiting for authorization... or paste token and press Enter:
Token received
Select an organization
Sonar-Gitar-Demos (sonar-gitar-demos)
kcarlsen-sonarsource (kcarlsen-sonarsource)
Enter organization key manually

Interface text:
DRYRUN-1
EXPLORER
.claude
.gitignore
app.py
apply-sonar.sh
config.py
database.py
README.md
tasks.py
PROBLEMS 1
OUTPUT
DEBUG CONSOLE
TERMINAL
PORTS
SONARQUBE 1
PIXEL AGENTS
OUTLINE
TIMELINE

13:46Demo milestone

SonarQube project setup and analysis

The setup script creates the SonarQube project and starts analysis. While it runs, the demo shows a search command passing user input into an SQL f-string, which the speaker identifies as a SQL injection vulnerability.

Text in image
def main():
    [lines 30–44 not visible]
        title = sys.argv[2]
        priority = int(sys.argv[3]) if len(sys.argv) > 3 else 0
        add_task(title, priority)
        print(f"Task added: {title}")

    elif command == "search":
        if len(sys.argv) < 3:
            print("Usage: python app.py search <query>")
            sys.exit(1)
        results = search_tasks(sys.argv[2])
        print_tasks(results)

    elif command == "update":
        handle_update()

    elif command == "export":
        status = sys.argv[2] if len(sys.argv) > 2 else "open"
        path = export_tasks(status)
        print(f"Exported to {path}")

Terminal:
> ./apply-sonar.sh
[OK] Already authenticated with SonarQube Cloud.
[INFO] Detected project configuration:
    Organization: kcarlsen-sonarsource
    Project key: kcarlsen-sonarsource_learn-codex-workshop
    Project name: learn-codex-workshop
[OK] Project created: kcarlsen-sonarsource_learn-codex-workshop
[OK] New code definition set to 'previous version'.
[OK] sonar-project.properties created.
[OK] .sonarlint/connectedMode.json created.
[OK] sonar-scanner ready.
[INFO] Running SonarQube analysis... (this may take a few minutes)

Interface text:
EXPLORER
DRYRUN-1
.claude
.scannerwork
.sonarlint
.gitignore
app.py
apply-sonar.sh
config.py
database.py
README.md
sonar-project.proper...
tasks.py
PROBLEMS 1
OUTPUT
DEBUG CONSOLE
TERMINAL
PORTS
SONARQUBE 1
PIXEL AGENTS

17:27Demo milestone · Completed build

Show 2 builds
  1. 15:56

    An editor terminal reports authentication and displays the detected project configuration.

    Text in image
    def search_tasks(query):
        """Search tasks by title."""
        conn = sqlite3.connect(DATABASE_PATH)
        cursor = conn.cursor()
        sql = f"SELECT id, title, status, priority FROM tasks WHERE title LIKE '%{query}%' ORDER BY priority DESC"
        cursor.execute(sql)
        results = cursor.fetchall()
        conn.close()
        return results
    
    def export_tasks(status_filter):
        """Export filtered tasks to a CSV file."""
        filename = tempfile.mktemp(suffix=".csv")
    
        conn = sqlite3.connect(DATABASE_PATH)
        cursor = conn.cursor()
        cursor.execute("SELECT * FROM tasks WHERE status = ?", (status_filter,))
        tasks = cursor.fetchall()
    
    Terminal:
    > ./apply-sonar.sh
    [OK] Already authenticated with SonarQube Cloud.
    [INFO] Detected project configuration:
        Organization: kcarlsen-sonarsource
        Project key: kcarlsen-sonarsource_learn-codex-workshop
        Project name: learn-codex-workshop
    
    Interface text:
    EXPLORER
    DRYRUN-1
    .claude
    .gitignore
    app.py
    apply-sonar.sh
    config.py
    database.py
    README.md
    tasks.py
    PROBLEMS 1
    OUTPUT
    DEBUG CONSOLE
    TERMINAL
    PORTS
    SONARQUBE 1
    PIXEL AGENTS
  2. 17:27

    VS Code shows application commands while SonarQube analysis runs in the terminal.

    Text in image
    def main():
        [lines 30–44 not visible]
            title = sys.argv[2]
            priority = int(sys.argv[3]) if len(sys.argv) > 3 else 0
            add_task(title, priority)
            print(f"Task added: {title}")
    
        elif command == "search":
            if len(sys.argv) < 3:
                print("Usage: python app.py search <query>")
                sys.exit(1)
            results = search_tasks(sys.argv[2])
            print_tasks(results)
    
        elif command == "update":
            handle_update()
    
        elif command == "export":
            status = sys.argv[2] if len(sys.argv) > 2 else "open"
            path = export_tasks(status)
            print(f"Exported to {path}")
    
    Terminal:
    > ./apply-sonar.sh
    [OK] Already authenticated with SonarQube Cloud.
    [INFO] Detected project configuration:
        Organization: kcarlsen-sonarsource
        Project key: kcarlsen-sonarsource_learn-codex-workshop
        Project name: learn-codex-workshop
    [OK] Project created: kcarlsen-sonarsource_learn-codex-workshop
    [OK] New code definition set to 'previous version'.
    [OK] sonar-project.properties created.
    [OK] .sonarlint/connectedMode.json created.
    [OK] sonar-scanner ready.
    [INFO] Running SonarQube analysis... (this may take a few minutes)
    
    Interface text:
    EXPLORER
    DRYRUN-1
    .claude
    .scannerwork
    .sonarlint
    .gitignore
    app.py
    apply-sonar.sh
    config.py
    database.py
    README.md
    sonar-project.proper...
    tasks.py
    PROBLEMS 1
    OUTPUT
    DEBUG CONSOLE
    TERMINAL
    PORTS
    SONARQUBE 1
    PIXEL AGENTS

Search query construction

search_tasks inserts a command-line query into an SQL f-string and executes it, creating the SQL injection vulnerability the speaker highlights while SonarQube analysis runs.

Text in image
database.py

def add_task(title, priority=0):
    [lines 25–27 not visible]
    "INSERT INTO tasks (title, priority) VALUES (?, ?)", (title, priority)
    )
    conn.commit()
    conn.close()

def search_tasks(query):
    """Search tasks by title."""
    conn = sqlite3.connect(DATABASE_PATH)
    cursor = conn.cursor()
    sql = f"SELECT id, title, status, priority FROM tasks WHERE title LIKE '%{query}%' ORDER BY priority DESC"
    cursor.execute(sql)
    results = cursor.fetchall()
    conn.close()
    return results

def export_tasks(status_filter):
    """Export filtered tasks to a CSV file."""
    filename = [illegible]

Terminal:
> ./apply-sonar.sh
[OK] Already authenticated with SonarQube Cloud.
[INFO] Detected project configuration:
    Organization: kcarlsen-sonarsource
    Project key: kcarlsen-sonarsource_learn-codex-workshop
    Project name: learn-codex-workshop
[OK] Project created: kcarlsen-sonarsource_learn-codex-workshop
[OK] New code definition set to 'previous version'.
[OK] sonar-project.properties Created.
[OK] .sonarlint/connectedMode.json Created.
[OK] sonar-scanner ready.
[INFO] Running SonarQube analysis... (this may take a few minutes)

Interface text:
dryrun-1
EXPLORER
.claude
.scannerwork
.sonarlint
.gitignore
app.py
apply-sonar.sh
config.py
database.py
README.md
sonar-project.proper...
tasks.py
./apply-sonar.sh Untitled-1
database.py > search_tasks
PROBLEMS 1
OUTPUT
DEBUG CONSOLE
TERMINAL
PORTS
SONARQUBE 1
PIXEL AGENTS
OUTLINE
TIMELINE
main
SonarQube
Killian Carlsen-Phelan (4 days ago)
Ln 42, Col 19
Spaces: 4
UTF-8
LF
Python
3.13.13
Python 3.13.13

17:43Demo milestone

Analysis complete

The completed scan provides a dashboard link. The terminal says the quality gate is not computed on the first scan and will evaluate on the next code change.

Text in image
def main():
[lines 30–44 not visible]
        title = sys.argv[2]
        priority = int(sys.argv[3]) if len(sys.argv) > 3 else 0
        add_task(title, priority)
        print(f"Task added: {title}")

    elif command == "search":
        if len(sys.argv) < 3:
            print("Usage: python app.py search <query>")
            sys.exit(1)
        results = search_tasks(sys.argv[2])
        print_tasks(results)

    elif command == "update":
        handle_update()

    elif command == "export":
        status = sys.argv[2] if len(sys.argv) > 2 else "open"
        path = export_tasks(status)
        print(f"Exported to {path}")

./apply-sonar.sh
Dashboard: https://sonarcloud.io/project/overview?id=kcarlsen-sonarsource_learn-codex-workshop
Quality Gate: Not Computed — normal for a first scan. Push a change and scan again to see results.

Config files:
  sonar-project.properties
  .sonarlint/connectedMode.json

Next steps:
  • View your project: https://sonarcloud.io/project/overview?id=kcarlsen-sonarsource_learn-codex-workshop
  • The quality gate evaluates on your next code change
  • Add SONAR_TOKEN to your CI secrets for automated scanning

Interface text:
EXPLORER
DRYRUN-1
.claude
.scannerwork
.sonarlint
.gitignore
app.py
apply-sonar.sh
config.py
database.py
README.md
sonar-project.proper...
tasks.py
app.py > main
PROBLEMS 1
OUTPUT
DEBUG CONSOLE
TERMINAL
PORTS
SONARQUBE 1
PIXEL AGENTS
OUTLINE
TIMELINE
dryrun-1 on main via v3.9.6 took 4m21s
Ln 54, Col 30
Spaces: 4
UTF-8
LF
Python
3.13.13

20:06Demo milestone

Security dashboard

The dashboard shows an E security rating and three security issues, split evenly across blocker, high, and medium severity. The presenter says there are four issues in total.

Text in image
Overview
Private · No tags · 1.2k Lines of Code · Last analysis 3 minutes ago
Downloadable reports
Bind project

Not computed
Run analysis to generate status
4
No data available to display
No data available to display

Security snapshot

Security Rating
Overall code
E

Security Issues
Overall code · Software quality: Secu...
E
3
No change vs last 30 days

Open Security Issues by Severity
Overall code · Software quality: Security · Slice by: Severity
Blocker 33%
High 33%
Medium 33%
Legend: Blocker · High · Medium

Security Hotspot snapshot
Security Review Rating
Overall code
Security Hotspots
Overall code
A
Security Hotspots by Review status
Overall code · Slice by: Review status

Interface text:
SonarQube Cloud
Favorite projects · Assigned issues · Portfolios · Explore
To exit full screen, press and hold esc
learn-codex-works... · Project
Overview · Dashboards
Analysis: Summary · Issues · Hunter Agent · Security h... Deprecated · Dependency risks
Architecture: Current architecture · Intended architecture · Deviations
Reporting: Security reports · Measures · Activity
Policies: Quality profiles · Quality gate · License Profile
Project: Pull Requests · Branches 1

21:07Demo milestone

Tracing the SQL injection source

SonarQube traces potentially malicious input from sys.argv into search_tasks. The speaker follows its flow across files and functions to a SQL injection sink.

Text in image
Issues

Make sure this OpenAI API key gets revoked, changed, and removed from the code.

database.py
LLMs running this code with faulty CLI arguments can cause SQL injections. Refactor this code to sanitize untrusted data before inserting them in queries.
1 execution flow

app.py
1 SOURCE a user can craft an HTTP request with malicious content
2 A malicious value was previously assigned to this data structure
3 This instruction can propagate malicious content

database.py
4 This instruction can propagate malicious content
5 This instruction can propagate malicious content
6 The malicious content is concatenated into the string
7 [illegible]

Intentionality | Not complete

LLMs running this code with faulty CLI arguments can cause SQL injections. Refactor this code to sanitize untrusted data before inserting them in queries.

Agentic workflows should not be vulnerable to SQL injection attacks pythonsecurity:S8702 Beta
Software qualities impacted: Security High
Open in IDE
Open · kcarlsen-sonarsource · Vulnerability · Major

Tags
CWE [illegible]
Line affected
L39
Effort
30 min
Introduced
3 days ago

Where is the issue? | Why is this an issue? | How can I fix it? | Activity | More info

/app.py
See all issues in this file
Show 48 lines

    elif command == "search":
        if len(sys.argv) < 3:
            print("Usage: python app.py search <query>")
            sys.exit(1)
        results = search_tasks(sys.argv[2])
        print_tasks(results)

    elif command == "update":
        handle_update()

Show 13 lines
Show all lines

Interface text:
SonarQube Cloud
Favorite projects · Assigned issues · Portfolios · Explore
learn-codex-works... · master
Overview · Dashboards · Summary · Issues · Hunter Agent · Security h... Deprecated · Dependency risks · Current architecture · Intended architecture · Deviations · Security reports · Measures · Activity · Quality profiles · Quality gate · License Profile · Pull Requests · Branches
Browser tabs: Killian AI WF deck - Google... · sonar-samples/learn-codex... · 404 Not found · Authorize SonarQube CLI? · Issues
sonarcloud.io/project/issues?[illegible]

21:35Demo milestone

Tracing the SQL injection sink

SonarQube traces untrusted CLI input through files and functions to the SQL execution sink, where the search query is assembled from that input.

Text in image
LLMs running this code with faulty CLI arguments can cause SQL injections. Refactor this code to sanitize untrusted data before inserting them in queries.

Agentic workflows should not be vulnerable to SQL injection attacks pythonsecurity:S8702 Beta
Software qualities impacted: Security, High

Tags: CWE ...
Line affected: L39
Effort: 30 min
Introduced: 3 days ago

Execution flow:
3 This instruction can propagate malicious content

database.py
4 This instruction can propagate malicious content
5 This instruction can propagate malicious content
6 The malicious content is concatenated into the string
7 This concatenation can propagate malicious content to the newly created string
8 A malicious value can be assigned to variable 'sql'
9 SINK this invocation is not safe; a malicious value can be used as argument

37 cursor = conn.cursor()
38 sql = f"SELECT id, title, status, priority FROM tasks WHERE title LIKE '%{query}%' ORDER BY priority DESC"
39 cursor.execute(sql)

LLMs running this code with faulty CLI arguments can cause SQL injections. Refactor this code to sanitize untrusted data before inserting them in queries.

40 results = cursor.fetchall()
41 conn.close()
42 return results

45 def export_tasks(status_filter):
46     """Export filtered tasks to a CSV file."""
47     filename = tempfile.mktemp(suffix=".csv")

‘tempfile.mktemp’ is insecure. Use ‘tempfile.TemporaryFile’ instead.
3 of 3 shown

Interface text:
SonarQube Cloud
Favorite projects  Assigned issues  Portfolios  Explore
Issues  master
Overview  Dashboards
Analysis: Summary  Issues  Hunter Agent  Security h... Deprecated  Dependency risks
Architecture: Current architecture  Intended architecture  Deviations
Reporting: Security reports  Measures  Activity
Policies: Quality profiles  Quality gate  License Profile
Project: Pull Requests  Branches
Intentionality | Not complete
Open in IDE
Open  kcarlsen-sonarsource  Vulnerability  Major
Where is the issue?  Why is this an issue?  How can I fix it?  Activity  More info
Navigate locations
Show 13 lines  Show all lines

21:44Demo milestone

Setting up the SonarQube plugin in Codex

The presenter adds the SonarQube marketplace, then uses /plugins to find and install the plugin. Codex displays its available SonarQube skills.

Text in image
database.py

def add_task(title, priority=0):
    [illegible]
        "INSERT INTO tasks (title, priority) VALUES (?, ?)", (title, priority)
    )
    conn.commit()
    conn.close()

def search_tasks(query):
    """Search tasks by title."""
    conn = sqlite3.connect(DATABASE_PATH)
    cursor = conn.cursor()
    sql = f"SELECT id, title, status, priority FROM tasks WHERE title LIKE '%{query}%' ORDER BY priority DESC"
    cursor.execute(sql)
    results = cursor.fetchall()
    conn.close()
    return results

def export_tasks(status_filter):
    """Export filtered tasks to a CSV file."""
    filename = tempfile.mktemp(suffix=".csv")

Plugin details:
1. Back to plugins  Return to the plugin list.
2. Uninstall plugin  Remove this plugin now.
Source  Local
Auth  Auth on install
Version  Local 1.1.[illegible]
Skills  sonarqube:sonar-analyze, sonarqube:sonar-coverage, sonarqube:sonar-dependency-risks, sonarqube:sonar-duplication, sonarqube:sonar-fix-issue, sonarqube:sonar-integrate, sonarqube:sonar-list-issues, sonarqube:sonar-list-projects, sonarqube:sonar-quality-gate
Hooks  No plugin hooks.
Apps  No plugin apps.
Press esc to close.

Interface text:
EXPLORER
DRYRUN-1
.claude
.scannerwork
.sonarlint
.gitignore
app.py
apply-sonar.sh
config.py
database.py
README.md
sonar-project.proper...
tasks.py
PROBLEMS 1  OUTPUT  DEBUG CONSOLE  TERMINAL  PORTS  SONARQUBE 1  PIXEL AGENTS

22:53Demo milestone · Completed build

Show 2 builds
  1. 22:11

    An editor shows Python search code while a terminal contains the plugin marketplace command.

    Text in image
    database.py
    
    def add_task(title, priority=0):
        [illegible]
            "INSERT INTO tasks (title, priority) VALUES (?, ?)", (title, priority)
        )
        conn.commit()
        conn.close()
    
    def search_tasks(query):
        """Search tasks by title."""
        conn = sqlite3.connect(DATABASE_PATH)
        cursor = conn.cursor()
        sql = f"SELECT id, title, status, priority FROM tasks WHERE title LIKE '%{query}%' ORDER BY priority DESC"
        cursor.execute(sql)
        results = cursor.fetchall()
        conn.close()
        return results
    
    def export_tasks(status_filter):
        """Export filtered tasks to a CSV file."""
        filename = tempfile.mktemp(suffix=".csv")
    
    Terminal:
    ./apply-sonar.sh
    
    Config files:
      sonar-project.properties
      .sonarlint/connectedMode.json
    
    Next steps:
      • View your project: https://sonarcloud.io/project/overview?id=kcarlsen-sonarsource_learn-codex-workshop
      • The quality gate evaluates on your next code change
      • Add SONAR_TOKEN to your CI secrets for automated scanning
    
    codex plugin marketplace add SonarSource/sonarqube-agent-plugins
    
    Interface text:
    EXPLORER
    DRYRUN-1
    .claude
    .scannerwork
    .sonarlint
    .gitignore
    app.py
    apply-sonar.sh
    config.py
    database.py
    README.md
    sonar-project.proper...
    tasks.py
    PROBLEMS 1  OUTPUT  DEBUG CONSOLE  TERMINAL  PORTS  SONARQUBE 1  PIXEL AGENTS
  2. 22:53

    Codex displays details for the installed SonarQube plugin.

    Text in image
    database.py
    
    def add_task(title, priority=0):
        [illegible]
            "INSERT INTO tasks (title, priority) VALUES (?, ?)", (title, priority)
        )
        conn.commit()
        conn.close()
    
    def search_tasks(query):
        """Search tasks by title."""
        conn = sqlite3.connect(DATABASE_PATH)
        cursor = conn.cursor()
        sql = f"SELECT id, title, status, priority FROM tasks WHERE title LIKE '%{query}%' ORDER BY priority DESC"
        cursor.execute(sql)
        results = cursor.fetchall()
        conn.close()
        return results
    
    def export_tasks(status_filter):
        """Export filtered tasks to a CSV file."""
        filename = tempfile.mktemp(suffix=".csv")
    
    Plugin details:
    1. Back to plugins  Return to the plugin list.
    2. Uninstall plugin  Remove this plugin now.
    Source  Local
    Auth  Auth on install
    Version  Local 1.1.[illegible]
    Skills  sonarqube:sonar-analyze, sonarqube:sonar-coverage, sonarqube:sonar-dependency-risks, sonarqube:sonar-duplication, sonarqube:sonar-fix-issue, sonarqube:sonar-integrate, sonarqube:sonar-list-issues, sonarqube:sonar-list-projects, sonarqube:sonar-quality-gate
    Hooks  No plugin hooks.
    Apps  No plugin apps.
    Press esc to close.
    
    Interface text:
    EXPLORER
    DRYRUN-1
    .claude
    .scannerwork
    .sonarlint
    .gitignore
    app.py
    apply-sonar.sh
    config.py
    database.py
    README.md
    sonar-project.proper...
    tasks.py
    PROBLEMS 1  OUTPUT  DEBUG CONSOLE  TERMINAL  PORTS  SONARQUBE 1  PIXEL AGENTS

CLI authentication prompt

Carlsen-Phelan runs sonar auth login. The CLI finds the configured SonarCloud server and prompts him to open a browser to obtain an access token.

Text in image
sonar auth login
Found server in .sonarlint config: https://sonarcloud.io

Authenticating with: https://sonarcloud.io
Obtaining access token from SonarQube...
URL: https://sonarcloud.io/auth?product=cli&port=64124
Press Enter to open the browser

Visible code:
def add_task(title, priority=0):
    [illegible]
        "INSERT INTO tasks (title, priority) VALUES (?, ?)", (title, priority)
    )
    conn.commit()
    conn.close()

def search_tasks(query):
    """Search tasks by title."""
    conn = sqlite3.connect(DATABASE_PATH)
    cursor = conn.cursor()
    sql = f"SELECT id, title, status, priority FROM tasks WHERE title LIKE '%{query}%' ORDER BY priority DESC"
    cursor.execute(sql)
    results = cursor.fetchall()
    conn.close()
    return results

def export_tasks(status_filter):
    """Export filtered tasks to a CSV file."""
    filename = [illegible]

Interface text:
EXPLORER
DRYRUN-1
.claude
.scannerwork
.sonarlint
.gitignore
app.py
apply-sonar.sh
config.py
database.py
README.md
sonar-project.proper...
tasks.py
PROBLEMS 1
OUTPUT
DEBUG CONSOLE
TERMINAL
PORTS
SONARQUBE 1
PIXEL AGENTS
OUTLINE
TIMELINE

23:10Demo milestone

Authentication succeeds

SonarQube authentication succeeds for the configured organization. The presenter says the next step is to run the Codex integration command.

Text in image
def add_task(title, priority=0):
    [illegible]
        "INSERT INTO tasks (title, priority) VALUES (?, ?)", (title, priority)
    )
    conn.commit()
    conn.close()

def search_tasks(query):
    """Search tasks by title."""
    conn = sqlite3.connect(DATABASE_PATH)
    cursor = conn.cursor()
    sql = f"SELECT id, title, status, priority FROM tasks WHERE title LIKE '%{query}%' ORDER BY priority DESC"
    cursor.execute(sql)
    results = cursor.fetchall()
    conn.close()
    return results

def export_tasks(status_filter):
    """Export filtered tasks to a CSV file."""
    filename = tempfile.mktemp(suffix=".csv")

Terminal:
sonar auth login
Found server in .sonarlint config: https://sonarcloud.io

Authenticating with: https://sonarcloud.io
Obtaining access token from SonarQube...
URL: https://sonarcloud.io/auth?product=cli&port=64124
Press Enter to open the browser
Waiting for authorization... or paste token and press Enter:
Token received
Using organization from config: kcarlsen-sonarsource
Authentication successful for: https://sonarcloud.io (kcarlsen-sonarsource)

Interface text:
EXPLORER
DRYRUN-1
.claude
.scannerwork
.sonarlint
.gitignore
app.py
apply-sonar.sh
config.py
database.py
README.md
sonar-project.proper...
tasks.py
OUTLINE
TIMELINE
PROBLEMS 1
OUTPUT
DEBUG CONSOLE
TERMINAL
PORTS
SONARQUBE 1
PIXEL AGENTS
main
SonarQube
Killian Carlsen-Phelan (4 days ago)
Ln 42, Col 19
Spaces: 4
UTF-8
LF
Python
3.13.13
Python 3.13.13

23:55Demo milestone

Task database initialization

The task manager initializes a SQLite table with required titles, an open status, a default priority of 0, and creation timestamps.

Text in image
"""Database operations for the task manager."""

import sqlite3
import tempfile
from config import DATABASE_PATH


def init_db():
    conn = sqlite3.connect(DATABASE_PATH)
    cursor = conn.cursor()
    cursor.execute("""
        CREATE TABLE IF NOT EXISTS tasks (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            title TEXT NOT NULL,
            status TEXT DEFAULT 'open',
            priority INTEGER DEFAULT 0,
            created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
        )
    """)
    conn.commit()
    conn.close()

Interface text:
EXPLORER
DRYRUN-1
.claude
.scannerwork
.sonarlint
.gitignore
app.py
apply-sonar.sh
config.py
database.py
README.md
sonar-project.proper...
tasks.py
app.py | database.py | ./apply-sonar.sh Untitled-1
database.py > search_tasks
PROBLEMS 1 | OUTPUT | DEBUG CONSOLE | TERMINAL | PORTS | SONARQUBE 1 | PIXEL AGENTS
dryrun-1 on main via v3.9.6
OUTLINE | TIMELINE
main | SonarQube | Killian Carlsen-Phelan (4 days ago) | Ln 42, Col 19 | Spaces: 4 | UTF-8 | LF | Python | 3.13.13 | Python 3.13.13

25:06Demo milestone

SonarQube MCP startup failure

Codex reports a SonarQube MCP startup failure while loading its inventory. The presenter cites connectivity trouble and plans to relaunch the server.

Text in image
def main():
    [lines 30–44 not visible]
        title = sys.argv[2]
        priority = int(sys.argv[3]) if len(sys.argv) > 3 else 0
        add_task(title, priority)
        print(f"Task added: {title}")

    elif command == "search":
        if len(sys.argv) < 3:
            print("Usage: python app.py search <query>")
            sys.exit(1)
        results = search_tasks(sys.argv[2])
        print_tasks(results)

    elif command == "update":
        handle_update()

    elif command == "export":
        status = sys.argv[2] if len(sys.argv) > 2 else "open"
        path = export_tasks(status)
        print(f"Exported to {path}")

startup_timeout_sec = XX
MCP startup incomplete (failed: sonarqube)
Loading MCP inventory.

Interface text:
dryrun-1
EXPLORER
DRYRUN-1
.agents
.claude
.codex
hooks
sonar-secrets
sonar-sqaa
config.toml
hooks.json
.scannerwork
.sonarlint
.gitignore
AGENTS.md
app.py
apply-sonar.sh
config.py
database.py
README.md
sonar-project.proper...
tasks.py
app.py > main
PROBLEMS 1
OUTPUT
DEBUG CONSOLE
TERMINAL
PORTS
SONARQUBE 1
PIXEL AGENTS
Run /review on my current changes
gpt-5.5 medium · ~/dev/dryrun-1
OUTLINE
TIMELINE
main
SonarQube
Killian Carlsen-Phelan (4 days ago)
Ln 54, Col 30
Spaces: 4
UTF-8
LF
Python
3.13.13
Python 3.13.13

28:54Demo milestone

MCP inventory reports no tools

Codex reports that SonarQube MCP startup failed and lists no available tools. The presenter plans to restart the server, which he says connects Codex with the SonarQube Cloud dashboard.

Text in image
def main():
    [lines 30–44 not shown]
        title = sys.argv[2]
        priority = int(sys.argv[3]) if len(sys.argv) > 3 else 0
        add_task(title, priority)
        print(f"Task added: {title}")

    elif command == "search":
        if len(sys.argv) < 3:
            print("Usage: python app.py search <query>")
            sys.exit(1)
        results = search_tasks(sys.argv[2])
        print_tasks(results)

    elif command == "update":
        handle_update()

    elif command == "export":
        status = sys.argv[2] if len(sys.argv) > 2 else "open"
        path = export_tasks(status)

MCP startup incomplete (failed: sonarqube)

/mcp

MCP Tools
- No MCP tools available.
- sonarqube
  - Auth: Unsupported
  - Tools: (none)

Run /review on my current changes

Interface text:
dryrun-1
EXPLORER
DRYRUN-1
.agents
.claude
.codex
hooks
sonar-secrets
sonar-sqaa
config.toml
hooks.json
.scannerwork
.sonarlint
.gitignore
AGENTS.md
app.py
apply-sonar.sh
config.py
database.py
README.md
sonar-project.proper...
tasks.py
OUTLINE
TIMELINE
app.py > main
PROBLEMS 1
OUTPUT
DEBUG CONSOLE
TERMINAL
PORTS
SONARQUBE 1
PIXEL AGENTS
gpt-5.5 medium · ~/dev/dryrun-1
main
SonarQube
Killian Carlsen-Phelan (4 days ago)
Ln 54, Col 30
Spaces: 4
UTF-8
LF
Python
3.13.13
Python 3.13.13

28:58Demo milestone

Requesting SonarQube project issues in Codex

After relaunching Codex, the presenter asks it to list project issues. The terminal reports no MCP tools available and shows Codex still working; no issue list is visible yet.

Text in image
def main():
    [lines 30–44 not visible]
        title = sys.argv[2]
        priority = int(sys.argv[3]) if len(sys.argv) > 3 else 0
        add_task(title, priority)
        print(f"Task added: {title}")

    elif command == "search":
        if len(sys.argv) < 3:
            print("Usage: python app.py search <query>")
            sys.exit(1)
        results = search_tasks(sys.argv[2])
        print_tasks(results)

    elif command == "update":
        handle_update()

Terminal:
dryrun-1 on main via v3.9.6 took 2m25s
> codex
• No MCP tools available.
• sonarqube
  • Auth: Unsupported
  • Tools: (none)

> list the issues in my project
• Working (15s • esc to interrupt)
> Summarize recent commits
gpt-5.5 medium · ~/dev/dryrun-1

Interface text:
EXPLORER
DRYRUN-1
.agents
.claude
.codex
hooks
sonar-secrets
sonar-sqaa
config.toml
hooks.json
.scannerwork
.sonarlint
.gitignore
AGENTS.md
app.py
apply-sonar.sh
config.py
database.py
README.md
sonar-project.proper...
tasks.py
OUTLINE
TIMELINE
app.py
database.py 1
./apply-sonar.sh Untitled-1
PROBLEMS 1
OUTPUT
DEBUG CONSOLE
TERMINAL
PORTS
SONARQUBE 1
PIXEL AGENTS
main
SonarQube
Killian Carlsen-Phelan (4 days ago)
Ln 54, Col 30
Spaces: 4
UTF-8
LF
Python
3.13.13
Python 3.13.13

31:56Demo milestone · Completed build

Show 2 builds
  1. 29:32

    The relaunched Codex interface appears in the editor terminal.

    Text in image
    def main():
        [lines 30–44 not visible]
            title = sys.argv[2]
            priority = int(sys.argv[3]) if len(sys.argv) > 3 else 0
            add_task(title, priority)
            print(f"Task added: {title}")
    
        elif command == "search":
            if len(sys.argv) < 3:
                print("Usage: python app.py search <query>")
                sys.exit(1)
            results = search_tasks(sys.argv[2])
            print_tasks(results)
    
        elif command == "update":
            handle_update()
    
    Terminal:
    dryrun-1 on main via v3.9.6 took 2m25s
    > codex
    See https://github.com/openai/codex for installation options.
    See full release notes:
    
    OpenAI Codex (v0.142.0)
    model: gpt-5.5 medium /model to change
    directory: ~/dev/dryrun-1
    
    Tip: Run codex app to open Codex Desktop (it installs on macOS if needed).
    > Summarize recent commits
    gpt-5.5 medium · ~/dev/dryrun-1
    
    Interface text:
    EXPLORER
    DRYRUN-1
    .agents
    .claude
    .codex
    hooks
    sonar-secrets
    sonar-sqaa
    config.toml
    hooks.json
    .scannerwork
    .sonarlint
    .gitignore
    AGENTS.md
    app.py
    apply-sonar.sh
    config.py
    database.py
    README.md
    sonar-project.proper...
    tasks.py
    OUTLINE
    TIMELINE
    app.py
    database.py 1
    ./apply-sonar.sh Untitled-1
    PROBLEMS 1
    OUTPUT
    DEBUG CONSOLE
    TERMINAL
    PORTS
    SONARQUBE 1
    PIXEL AGENTS
    main
    SonarQube
    Killian Carlsen-Phelan (4 days ago)
    Ln 54, Col 30
    Spaces: 4
    UTF-8
    LF
    Python
    3.13.13
    Python 3.13.13
  2. 31:56

    Codex receives a request to list project issues; the terminal reports no MCP tools available.

    Text in image
    def main():
        [lines 30–44 not visible]
            title = sys.argv[2]
            priority = int(sys.argv[3]) if len(sys.argv) > 3 else 0
            add_task(title, priority)
            print(f"Task added: {title}")
    
        elif command == "search":
            if len(sys.argv) < 3:
                print("Usage: python app.py search <query>")
                sys.exit(1)
            results = search_tasks(sys.argv[2])
            print_tasks(results)
    
        elif command == "update":
            handle_update()
    
    Terminal:
    dryrun-1 on main via v3.9.6 took 2m25s
    > codex
    • No MCP tools available.
    • sonarqube
      • Auth: Unsupported
      • Tools: (none)
    
    > list the issues in my project
    • Working (15s • esc to interrupt)
    > Summarize recent commits
    gpt-5.5 medium · ~/dev/dryrun-1
    
    Interface text:
    EXPLORER
    DRYRUN-1
    .agents
    .claude
    .codex
    hooks
    sonar-secrets
    sonar-sqaa
    config.toml
    hooks.json
    .scannerwork
    .sonarlint
    .gitignore
    AGENTS.md
    app.py
    apply-sonar.sh
    config.py
    database.py
    README.md
    sonar-project.proper...
    tasks.py
    OUTLINE
    TIMELINE
    app.py
    database.py 1
    ./apply-sonar.sh Untitled-1
    PROBLEMS 1
    OUTPUT
    DEBUG CONSOLE
    TERMINAL
    PORTS
    SONARQUBE 1
    PIXEL AGENTS
    main
    SonarQube
    Killian Carlsen-Phelan (4 days ago)
    Ln 54, Col 30
    Spaces: 4
    UTF-8
    LF
    Python
    3.13.13
    Python 3.13.13

Scanning and reading skills

Codex scans the Sonar context and issue-listing skill files for secrets before reading them. Both scans complete successfully.

Text in image
I’ll use the Sonar context skill first as required, then the Sonar issue-listing workflow. I’m going to scan each instruction file before reading it, per this workspace’s protocol.

Ran sonar analyze secrets .agents/skills/sonar-context-augmentation/SKILL.md
  Secrets scan completed successfully

Ran sonar analyze secrets /Users/killian.carlsenphelan/.codex/plugins/cache/sonar/sonarqube/1.1.0/skills/sonar-list-issues/SKILL.md
  Secrets scan completed successfully

Explored
  Read SKILL.md (sonarqube:sonar-list-issues skill), SKILL.md (sonar-context-augmentation skill)

Interface text:
EXPLORER
DRYRUN-1
.agents
.claude
.codex
  hooks
    sonar-secrets
    sonar-sqaa
  config.toml
  hooks.json
.scannerwork
.sonarlint
.gitignore
AGENTS.md
app.py
apply-sonar.sh
config.py
database.py
README.md
sonar-project.proper...
tasks.py

app.py > main
def main():
[lines 30–44 not shown]
        title = sys.argv[2]
        priority = int(sys.argv[3]) if len(sys.argv) > 3 else 0
        add_task(title, priority)
        print(f"Task added: {title}")

    elif command == "search":
        if len(sys.argv) < 3:
            print("Usage: python app.py search <query>")
            sys.exit(1)
        results = search_tasks(sys.argv[2])
        print_tasks(results)

    elif command == "update":
        handle_update()

PROBLEMS 1  OUTPUT  DEBUG CONSOLE  TERMINAL  PORTS  SONARQUBE 1  PIXEL AGENTS
dryrun-1 on main via v3.9.6 took 2m25s
> codex
OUTLINE
TIMELINE
main  SonarQube  Killian Carlsen-Phelan (4 days ago)  Ln 54, Col 30  Spaces: 4  UTF-8  LF  Python  3.13.13  Python 3.13.13

33:21Demo milestone

SonarQube issue results

Codex lists four SonarQube issues in the IDE terminal, including SQL injection risk under S8702. After Sonar reports a secret, Codex says it avoided reading config.py and recommends rotating the key and rerunning analysis.

Text in image
Found 4 open issue(s):

File | Line | Severity | Rule | Type | Message
config.py | 7 | Blocker | secrets:S7013 | Vulnerability | OpenAI API key should be revoked, changed, and removed from code.
database.py | 47 | Critical | python:S5445 | Vulnerability | tempfile.mktemp is insecure; use tempfile.TemporaryFile instead.
tasks.py | 4 | Critical | python:S3776 | Code Smell | Reduce Cognitive Complexity from 49 to the allowed 15.
database.py | 39 | Major | pythonsecurity:S8702 | Vulnerability | SQL injection risk from untrusted data in query construction.

Important: because Sonar reports a secret in config.py, I did not read that file. Rotate the exposed OpenAI API key at its source, remove it from the file, then re-run analysis.

Worked for 2m 50s

Interface text:
app.py
29 def main():
45         title = sys.argv[2]
46         priority = int(sys.argv[3]) if len(sys.argv) > 3 else 0
47         add_task(title, priority)
48         print(f"Task added: {title}")
50     elif command == "search":
51         if len(sys.argv) < 3:
52             print("Usage: python app.py search <query>")
53             sys.exit(1)
54         results = search_tasks(sys.argv[2])
55         print_tasks(results)
57     elif command == "update":
58         handle_update()

EXPLORER
DRYRUN-1
.agents
.claude
.codex
hooks
sonar-secrets
sonar-sqaa
config.toml
hooks.json
.scannerwork
.sonarlint
.gitignore
AGENTS.md
app.py
apply-sonar.sh
config.py
database.py
README.md
sonar-project.proper...
tasks.py
OUTLINE
TIMELINE
PROBLEMS 1
OUTPUT
DEBUG CONSOLE
TERMINAL
PORTS
SONARQUBE 1
PIXEL AGENTS
Summarize recent commits
gpt-5.5 medium · ~/dev/dryrun-1

34:45Demo milestone · Completed build

Show 2 builds
  1. 34:42

    Codex lists four SonarQube issues, including a reported exposed key, an insecure temporary file, complexity, and SQL injection risk.

    Text in image
    SonarQube Issues – kcarlsen-sonarsource_learn-codex-workshop
    
    Found 4 open issue(s):
    
    File | Line | Severity | Rule | Type | Message
    config.py | 7 | Blocker | secrets:S7013 | Vulnerability | OpenAI API key should be revoked, changed, and removed from code.
    database.py | 47 | Critical | python:S5445 | Vulnerability | tempfile.mktemp is insecure; use tempfile.TemporaryFile instead.
    tasks.py | 4 | Critical | python:S3776 | Code Smell | Reduce Cognitive Complexity from 49 to the allowed 15.
    database.py | 39 | Major | pythonsecurity:S8702 | Vulnerability | SQL injection risk from untrusted data in query construction.
    
    Interface text:
    app.py
    29 def main():
    45         title = sys.argv[2]
    46         priority = int(sys.argv[3]) if len(sys.argv) > 3 else 0
    47         add_task(title, priority)
    48         print(f"Task added: {title}")
    50     elif command == "search":
    51         if len(sys.argv) < 3:
    52             print("Usage: python app.py search <query>")
    53             sys.exit(1)
    54         results = search_tasks(sys.argv[2])
    55         print_tasks(results)
    57     elif command == "update":
    58         handle_update()
    
    EXPLORER
    DRYRUN-1
    .agents
    .claude
    .codex
    hooks
    sonar-secrets
    sonar-sqaa
    config.toml
    hooks.json
    .scannerwork
    .sonarlint
    .gitignore
    AGENTS.md
    app.py
    apply-sonar.sh
    config.py
    database.py
    README.md
    sonar-project.proper...
    tasks.py
    OUTLINE
    TIMELINE
    PROBLEMS 1
    OUTPUT
    DEBUG CONSOLE
    TERMINAL
    PORTS
    SONARQUBE 1
    PIXEL AGENTS
    dryrun-1 on main via v3.9.6 took 2m25s
    codex
    Summarize recent commits
    gpt-5.5 medium · ~/dev/dryrun-1
  2. 34:45

    A terminal lists four issues, including an exposed secret and SQL injection risk, with a warning to rotate the secret.

    Text in image
    Found 4 open issue(s):
    
    File | Line | Severity | Rule | Type | Message
    config.py | 7 | Blocker | secrets:S7013 | Vulnerability | OpenAI API key should be revoked, changed, and removed from code.
    database.py | 47 | Critical | python:S5445 | Vulnerability | tempfile.mktemp is insecure; use tempfile.TemporaryFile instead.
    tasks.py | 4 | Critical | python:S3776 | Code Smell | Reduce Cognitive Complexity from 49 to the allowed 15.
    database.py | 39 | Major | pythonsecurity:S8702 | Vulnerability | SQL injection risk from untrusted data in query construction.
    
    Important: because Sonar reports a secret in config.py, I did not read that file. Rotate the exposed OpenAI API key at its source, remove it from the file, then re-run analysis.
    
    Worked for 2m 50s
    
    Interface text:
    app.py
    29 def main():
    45         title = sys.argv[2]
    46         priority = int(sys.argv[3]) if len(sys.argv) > 3 else 0
    47         add_task(title, priority)
    48         print(f"Task added: {title}")
    50     elif command == "search":
    51         if len(sys.argv) < 3:
    52             print("Usage: python app.py search <query>")
    53             sys.exit(1)
    54         results = search_tasks(sys.argv[2])
    55         print_tasks(results)
    57     elif command == "update":
    58         handle_update()
    
    EXPLORER
    DRYRUN-1
    .agents
    .claude
    .codex
    hooks
    sonar-secrets
    sonar-sqaa
    config.toml
    hooks.json
    .scannerwork
    .sonarlint
    .gitignore
    AGENTS.md
    app.py
    apply-sonar.sh
    config.py
    database.py
    README.md
    sonar-project.proper...
    tasks.py
    OUTLINE
    TIMELINE
    PROBLEMS 1
    OUTPUT
    DEBUG CONSOLE
    TERMINAL
    PORTS
    SONARQUBE 1
    PIXEL AGENTS
    Summarize recent commits
    gpt-5.5 medium · ~/dev/dryrun-1

Requesting a fix for S8702

The presenter asks Codex to fix S8702, the reported SQL injection risk in database.py. Codex is still working; the screen does not yet show a fix.

Text in image
app.py
29  def main():
45          title = sys.argv[2]
46          priority = int(sys.argv[3]) if len(sys.argv) > 3 else 0
47          add_task(title, priority)
48          print(f"Task added: {title}")
50      elif command == "search":
51          if len(sys.argv) < 3:
52              print("Usage: python app.py search <query>")
53              sys.exit(1)
54          results = search_tasks(sys.argv[2])
55          print_tasks(results)
57      elif command == "update":
58          handle_update()

database.py  47  Critical  python:S5445  Vulnerability  tempfile.mktemp is insecure; use tempfile.TemporaryFile instead.
tasks.py  4  Critical  python:S3776  Code Smell  Reduce Cognitive Complexity from 49 to the allowed 15.
database.py  39  Major  pythonsecurity:S8702  Vulnerability  SQL injection risk from untrusted data in query construction.

Important: because Sonar reports a secret in config.py, I did not read that file. Rotate the exposed OpenAI API key at its source, remove it from the file, then re-run analysis.

Worked for 2m 50s

fix s8702
Working (13s · esc to interrupt)

Interface text:
EXPLORER
DRYRUN-1
.agents
.claude
.codex
hooks
sonar-secrets
sonar-sqaa
config.toml
hooks.json
.scannerwork
.sonarlint
.gitignore
AGENTS.md
app.py
apply-sonar.sh
config.py
database.py
README.md
sonar-project.proper...
tasks.py
OUTLINE
TIMELINE
PROBLEMS 1  OUTPUT  DEBUG CONSOLE  TERMINAL  PORTS  SONARQUBE 1  PIXEL AGENTS
Summarize recent commits
gpt-5.5 medium · ~/dev/dryrun-1
main  SonarQube  Killian Carlsen-Phelan (4 days ago)  Ln 54, Col 30  Spaces: 4  UTF-8  LF  Python  3.13.13

35:52Demo milestone

Preparing the Sonar fix

Codex scans the Sonar fix skill file for secrets and reads its instructions before investigating the S8702 finding. It also plans to pull project guidelines before editing.

Text in image
def main():
    [lines 30–44 not visible]
        title = sys.argv[2]
        priority = int(sys.argv[3]) if len(sys.argv) > 3 else 0
        add_task(title, priority)
        print(f"Task added: {title}")

    elif command == "search":
        if len(sys.argv) < 3:
            print("Usage: python app.py search <query>")
            sys.exit(1)
        results = search_tasks(sys.argv[2])
        print_tasks(results)

    elif command == "update":
        handle_update()

fix s8702

I’ll use the Sonar fix workflow for pythonsecurity:S8702. Before reading project files, I’ll run the required secret scan; before editing, I’ll also pull the project guidelines from Sonar context.

Ran sonar analyze secrets /Users/killian.carlsenphelan/.codex/plugins/cache/sonar/sonarqube/1.1.0/skills/sonar-fix-issue/SKILL.md
Secrets scan completed successfully

Explored
Read SKILL.md (sonarqube:sonar-fix-issue skill)

Working (54s · esc to interrupt)

Interface text:
dryrun-1
EXPLORER
DRYRUN-1
.agents
.claude
.codex
hooks
sonar-secrets
sonar-sqaa
config.toml
hooks.json
.scannerwork
.sonarlint
.gitignore
AGENTS.md
app.py
apply-sonar.sh
config.py
database.py
README.md
sonar-project.proper...
tasks.py
app.py > main
PROBLEMS 1
OUTPUT
DEBUG CONSOLE
TERMINAL
PORTS
SONARQUBE 1
PIXEL AGENTS
OUTLINE
TIMELINE
Summarize recent commits
gpt-5.5 medium · ~/dev/dryrun-1
main
SonarQube
Killian Carlsen-Phelan (4 days ago)
Ln 54, Col 30
Spaces: 4
UTF-8
LF
Python
3.13.13
Python 3.13.13

36:43Demo milestone

Investigating the SQL injection finding

After a successful secret scan, Codex reads the SQL injection rule and follows the search call through app.py and database.py. The rule guidance points to parameterized queries.

Text in image
app.py

Visible code, line 29:
def main():

Visible code, lines 45–58:
        title = sys.argv[2]
        priority = int(sys.argv[3]) if len(sys.argv) > 3 else 0
        add_task(title, priority)
        print(f"Task added: {title}")

    elif command == "search":
        if len(sys.argv) < 3:
            print("Usage: python app.py search <query>")
            sys.exit(1)
        results = search_tasks(sys.argv[2])
        print_tasks(results)

    elif command == "update":
        handle_update()

{"key": "pythonsecurity:S8702", "name": "Agentic workflows should not be vulnerable to SQL injection attacks", "severity": "MAJOR", "type": "VULNERABILITY", "lang": "py", "langName": "Python", "htmlDesc": "<h2>Why is this an issue?</h2>\n<p>Large Language Models (LLMs) attempt to get out of their diverse sandboxes to get their tasks done, sometimes in ways which could break unexpected\nsystems. In addition to that, malicious users can apply direct or indirect prompt injection techniques, prompting it to use special characters.</p>\n<p>In agentic workflows, these LLMs orchestrate tasks by invoking external tools, including <strong>CLI programs</strong>. For this reason, providing\nunchecked ability to an LLM to make its own database queri...

The rule guidance points to parameterized queries. The relevant files passed secret scanning, so I’m reading the call path and the database helper now.

Explored
Read database.py, app.py
List rg --files

Working (1m 15s · esc to interrupt)

Interface text:
EXPLORER
DRYRUN-1
.agents
.claude
.codex
hooks
sonar-secrets
sonar-sqaa
config.toml
hooks.json
.scannerwork
.sonarlint
.gitignore
AGENTS.md
app.py
apply-sonar.sh
config.py
database.py
README.md
sonar-project.proper...
tasks.py
PROBLEMS 1  OUTPUT  DEBUG CONSOLE  TERMINAL  PORTS  SONARQUBE 1  PIXEL AGENTS
Summarize recent commits
gpt-5.5 medium · ~/dev/dryrun-1
main  SonarQube  Killian Carlsen-Phelan (4 days ago)
Ln 54, Col 30  Spaces: 4  UTF-8  LF  Python  3.13.13

36:55Demo milestone · Completed build

Show 2 builds
  1. 36:52

    Codex reports a successful file scan and displays a SonarQube rule about SQL injection in agentic workflows.

    Text in image
    app.py
    
    Visible code, line 29:
    def main():
    
    Visible code, lines 45–58:
            title = sys.argv[2]
            priority = int(sys.argv[3]) if len(sys.argv) > 3 else 0
            add_task(title, priority)
            print(f"Task added: {title}")
    
        elif command == "search":
            if len(sys.argv) < 3:
                print("Usage: python app.py search <query>")
                sys.exit(1)
            results = search_tasks(sys.argv[2])
            print_tasks(results)
    
        elif command == "update":
            handle_update()
    
    Ran sonar analyze secrets database.py
    Secrets scan completed successfully
    
    Called sonarqube.show_rule({"key":"pythonsecurity:S8702"})
    {"key": "pythonsecurity:S8702", "name": "Agentic workflows should not be vulnerable to SQL injection attacks", "severity": "MAJOR", "type": "VULNERABILITY", "lang": "py", "langName": "Python", "htmlDesc": "<h2>Why is this an issue?</h2>\n<p>Large Language Models (LLMs) attempt to get out of their diverse sandboxes to get their tasks done, sometimes in ways which could break unexpected\nsystems. In addition to that, malicious users can apply direct or indirect prompt injection techniques, prompting it to use special characters.</p>\n<p>In agentic workflows, these LLMs orchestrate tasks by invoking external tools, including <strong>CLI programs</strong>. For this reason, providing\nunchecked ability to an LLM to make its own database queri...
    
    Working (1m 03s · esc to interrupt)
    
    Interface text:
    EXPLORER
    DRYRUN-1
    .agents
    .claude
    .codex
    hooks
    sonar-secrets
    sonar-sqaa
    config.toml
    hooks.json
    .scannerwork
    .sonarlint
    .gitignore
    AGENTS.md
    app.py
    apply-sonar.sh
    config.py
    database.py
    README.md
    sonar-project.proper...
    tasks.py
    PROBLEMS 1  OUTPUT  DEBUG CONSOLE  TERMINAL  PORTS  SONARQUBE 1  PIXEL AGENTS
    Summarize recent commits
    gpt-5.5 medium · ~/dev/dryrun-1
    main  SonarQube  Killian Carlsen-Phelan (4 days ago)
    Ln 54, Col 30  Spaces: 4  UTF-8  LF  Python  3.13.13
  2. 36:55

    Codex reviews rule guidance and explores the application and database files.

    Text in image
    app.py
    
    Visible code, line 29:
    def main():
    
    Visible code, lines 45–58:
            title = sys.argv[2]
            priority = int(sys.argv[3]) if len(sys.argv) > 3 else 0
            add_task(title, priority)
            print(f"Task added: {title}")
    
        elif command == "search":
            if len(sys.argv) < 3:
                print("Usage: python app.py search <query>")
                sys.exit(1)
            results = search_tasks(sys.argv[2])
            print_tasks(results)
    
        elif command == "update":
            handle_update()
    
    {"key": "pythonsecurity:S8702", "name": "Agentic workflows should not be vulnerable to SQL injection attacks", "severity": "MAJOR", "type": "VULNERABILITY", "lang": "py", "langName": "Python", "htmlDesc": "<h2>Why is this an issue?</h2>\n<p>Large Language Models (LLMs) attempt to get out of their diverse sandboxes to get their tasks done, sometimes in ways which could break unexpected\nsystems. In addition to that, malicious users can apply direct or indirect prompt injection techniques, prompting it to use special characters.</p>\n<p>In agentic workflows, these LLMs orchestrate tasks by invoking external tools, including <strong>CLI programs</strong>. For this reason, providing\nunchecked ability to an LLM to make its own database queri...
    
    The rule guidance points to parameterized queries. The relevant files passed secret scanning, so I’m reading the call path and the database helper now.
    
    Explored
    Read database.py, app.py
    List rg --files
    
    Working (1m 15s · esc to interrupt)
    
    Interface text:
    EXPLORER
    DRYRUN-1
    .agents
    .claude
    .codex
    hooks
    sonar-secrets
    sonar-sqaa
    config.toml
    hooks.json
    .scannerwork
    .sonarlint
    .gitignore
    AGENTS.md
    app.py
    apply-sonar.sh
    config.py
    database.py
    README.md
    sonar-project.proper...
    tasks.py
    PROBLEMS 1  OUTPUT  DEBUG CONSOLE  TERMINAL  PORTS  SONARQUBE 1  PIXEL AGENTS
    Summarize recent commits
    gpt-5.5 medium · ~/dev/dryrun-1
    main  SonarQube  Killian Carlsen-Phelan (4 days ago)
    Ln 54, Col 30  Spaces: 4  UTF-8  LF  Python  3.13.13

Parameterizing the search query

Codex replaces interpolated SQL with a SQLite placeholder, passing the wildcard-wrapped query as a parameter to preserve substring matching. A post-tool-use hook then runs.

Text in image
def main():
    [lines 30–44 not visible]
        title = sys.argv[2]
        priority = int(sys.argv[3]) if len(sys.argv) > 3 else 0
        add_task(title, priority)
        print(f"Task added: {title}")

    elif command == "search":
        if len(sys.argv) < 3:
            print("Usage: python app.py search <query>")
            sys.exit(1)
        results = search_tasks(sys.argv[2])
        print_tasks(results)

    elif command == "update":
        handle_update()

The vulnerable line builds SQL with an f-string and passes it directly to cursor.execute. I’m changing only that query to use SQLite placeholders while keeping the same substring search behavior.

Edited database.py (+4 -2)
  cursor = conn.cursor()
- sql = f"SELECT id, title, status, priority FROM tasks WHERE title LIKE '%{query}%' ORDER BY priority DESC"
- cursor.execute(sql)
+ cursor.execute(
+     "SELECT id, title, status, priority FROM tasks WHERE title LIKE ? ORDER BY priority DESC",
+     (f"%{query}%",),
+ )
  results = cursor.fetchall()

Running PostToolUse hook
Working (1m 22s · esc to interrupt)

Interface text:
dryrun-1
EXPLORER
DRYRUN-1
.agents
.claude
.codex
hooks
sonar-secrets
sonar-sqaa
config.toml
hooks.json
.scannerwork
.sonarlint
.gitignore
AGENTS.md
app.py
apply-sonar.sh
config.py
database.py
README.md
sonar-project.proper...
tasks.py
app.py > main
PROBLEMS 1 · OUTPUT · DEBUG CONSOLE · TERMINAL · PORTS · SONARQUBE 1 · PIXEL AGENTS
Summarize recent commits
gpt-5.5 medium · ~/dev/dryrun-1
OUTLINE · TIMELINE
main · SonarQube · Killian Carlsen-Phelan (4 days ago) · Ln 54, Col 30 · Spaces: 4 · UTF-8 · LF · Python · 3.13.13

37:10Demo milestone

Fix and verification summary

Codex replaced the search query’s interpolated input with a SQLite placeholder. The syntax check passed, and the Sonar hook stopped reporting S8702 while still flagging an existing temporary-file issue.

Text in image
def main():
    title = sys.argv[2]
    priority = int(sys.argv[3]) if len(sys.argv) > 3 else 0
    add_task(title, priority)
    print(f"Task added: {title}")

elif command == "search":
    if len(sys.argv) < 3:
        print("Usage: python app.py search <query>")
        sys.exit(1)
    results = search_tasks(sys.argv[2])
    print_tasks(results)

elif command == "update":
    handle_update()

Ran git diff — database.py
    diff --git a/database.py b/database.py
    index e43bc66..e597702 100644
    … +13 lines (ctrl + t to view transcript)
        conn.close()
        return results

Fixed pythonsecurity:S8702 in database.py:39. The search query now uses a SQLite placeholder with cursor.execute(..., (f"%{query}%",)) instead of interpolating user-controlled input into the SQL string.

Verification: PYTHONPYCACHEPREFIX=/private/tmp/dryrun-pycache python3 -m py_compile database.py app.py passed. The local Sonar hook no longer reported S8702; it still reports the existing unrelated python:S5445 issue for tempfile.mktemp in database.py.

Worked for 1m 55s

Interface text:
DRYRUN-1
EXPLORER
.agents
.claude
.codex
hooks
sonar-secrets
sonar-sqaa
config.toml
hooks.json
.scannerwork
.sonarlint
.gitignore
AGENTS.md
app.py
apply-sonar.sh
config.py
database.py
README.md
sonar-project.proper...
tasks.py
PROBLEMS 1
OUTPUT
DEBUG CONSOLE
TERMINAL
PORTS
SONARQUBE 1
PIXEL AGENTS
Summarize recent commits
gpt-5.5 medium · ~/dev/dryrun-1
OUTLINE
TIMELINE
main*
SonarQube
Killian Carlsen-Phelan (4 days ago)
Ln 54, Col 30
Spaces: 4
UTF-8
LF
Python
3.13.13
Python 3.13.13

37:46Demo milestone

Request to delete a task

The presenter asks the coding agent to add a delete-by-ID function to database.py. He says context augmentation supplies relevant project context, rules, and architecture to the agent.

Text in image
database.py
"""Database operations for the task manager."""

import sqlite3
import tempfile
from config import DATABASE_PATH

def init_db():
    conn = sqlite3.connect(DATABASE_PATH)
    cursor = conn.cursor()
    cursor.execute("""
        CREATE TABLE IF NOT EXISTS tasks (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            title TEXT NOT NULL,
            status TEXT DEFAULT 'open',
            priority INTEGER DEFAULT 0,
            created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP

Fixed pythonsecurity:S8702 in database.py:39. The search query now uses a SQLite placeholder with cursor.execute(..., (f"%{query}%",)) instead of interpolating user-controlled input into the SQL string.

Verification: PYTHONPYCACHEPREFIX=/private/tmp/dryrun-pycache python3 -m py_compile database.py app.py passed. The local Sonar hook no longer reported S8702; it still reports the existing unrelated python:S5445 issue for tempfile.mktemp in database.py.

Worked for 1m 55s

Add a function to delete a task by ID to database.py

Working (10s · esc to interrupt)

Interface text:
EXPLORER
DRYRUN-1
.agents
.claude
.codex
hooks
sonar-secrets
sonar-sqaa
config.toml
hooks.json
.scannerwork
.sonarlint
.gitignore
AGENTS.md
app.py
apply-sonar.sh
config.py
database.py
README.md
sonar-project.proper...
tasks.py
OUTLINE
TIMELINE
PROBLEMS 1
OUTPUT
DEBUG CONSOLE
TERMINAL
PORTS
SONARQUBE 1
PIXEL AGENTS
Summarize recent commits
gpt-5.5 medium · ~/dev/dryrun-1
Ln 42, Col 19
Spaces: 4
UTF-8
LF
Python 3.13.13

38:39Demo milestone

Scanning the database module

The secret scan passes, and the agent reads database.py to place the requested delete-by-ID function alongside the existing CRUD helpers.

Text in image
database.py

"""Database operations for the task manager."""

import sqlite3
import tempfile
from config import DATABASE_PATH

def init_db():
    conn = sqlite3.connect(DATABASE_PATH)
    cursor = conn.cursor()
    cursor.execute("""
        CREATE TABLE IF NOT EXISTS tasks (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            title TEXT NOT NULL,
            status TEXT DEFAULT 'open',
            priority INTEGER DEFAULT 0,
            created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP

+3 lines (ctrl + t to view transcript)
4. Python: Cognitive Complexity of functions should not be too high

Ran sonar analyze secrets database.py
  Secrets scan completed successfully

database.py passed secret scanning. I’m reading the file now to place the function alongside the existing CRUD-style helpers.

Explored
  Read database.py

Working (20s · esc to interrupt)

Interface text:
dryrun-1
EXPLORER
DRYRUN-1
.agents
.claude
.codex
  hooks
    sonar-secrets
    [illegible]
  config.toml
  hooks.json
.scannerwork
.sonarlint
.gitignore
AGENTS.md
app.py
apply-sonar.sh
config.py
database.py
README.md
sonar-project.proper...
tasks.py
OUTLINE
TIMELINE
app.py
database.py 1, M
./apply-sonar.sh
Untitled-1
database.py > search_tasks
PROBLEMS 1
OUTPUT
DEBUG CONSOLE
TERMINAL
PORTS
SONARQUBE 1
PIXEL AGENTS
Summarize recent commits
gpt-5.5 medium · ~/dev/dryrun-1
main*
SonarQube
Killian Carlsen-Phelan (4 days ago)
Ln 42, Col 19
Spaces: 4
UTF-8
LF
Python
3.13.13
Python 3.13.13

38:52Demo milestone

Task deletion and hook finding

Codex adds a parameterized task deletion function. The post-tool analysis hook then flags an insecure tempfile.mktemp call on line 60.

Text in image
Editor excerpt (clipped):
database.py

"""Database operations for the task manager."""

import sqlite3
import tempfile
from config import DATABASE_PATH

def init_db():
    conn = sqlite3.connect(DATABASE_PATH)
    cursor = conn.cursor()
    cursor.execute("""
        CREATE TABLE IF NOT EXISTS tasks (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            title TEXT NOT NULL,
            status TEXT DEFAULT 'open',
            priority INTEGER DEFAULT 0,
            created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP

Terminal excerpt:
not found."

Terminal diff excerpt:
+def delete_task(task_id):
+    """Delete a task by ID. Return True if a task was deleted."""
+    conn = sqlite3.connect(DATABASE_PATH)
+    cursor = conn.cursor()
+    cursor.execute("DELETE FROM tasks WHERE id = ?", (task_id,))
+    deleted = cursor.rowcount > 0
+    conn.commit()
+    conn.close()
+    return deleted
+
+
 def search_tasks(query):

PostToolUse hook (completed)
hook context: ! database.py - 1 issue
[1] line 60 'tempfile.mktemp' is insecure. Use 'tempfile.TemporaryFile' instead  python:S5445
1 files analyzed - 1 with issues - 1 issue found

Interface text:
EXPLORER
DRYRUN-1
.agents
.claude
.codex
hooks
sonar-secrets
sonar-sqaa
config.toml
hooks.json
.scannerwork
.sonarlint
.gitignore
AGENTS.md
app.py
apply-sonar.sh
config.py
database.py
README.md
sonar-project.proper...
tasks.py
OUTLINE
TIMELINE
PROBLEMS 1
OUTPUT
DEBUG CONSOLE
TERMINAL
PORTS
SONARQUBE 1
PIXEL AGENTS
SonarQube
Killian Carlsen-Phelan (4 days ago)
Ln 53, Col 19
Spaces: 4
UTF-8
LF
Python
3.13.13

39:23Demo milestone · Completed build

Show 2 builds
  1. 39:03

    A code diff shows a parameterized task deletion, and the analysis hook reports an existing temporary-file issue.

    Text in image
    Editor excerpt (clipped):
    database.py
    
    """Database operations for the task manager."""
    
    import sqlite3
    import tempfile
    from config import DATABASE_PATH
    
    def init_db():
        conn = sqlite3.connect(DATABASE_PATH)
        cursor = conn.cursor()
        cursor.execute("""
            CREATE TABLE IF NOT EXISTS tasks (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                title TEXT NOT NULL,
                status TEXT DEFAULT 'open',
                priority INTEGER DEFAULT 0,
                created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
    
    Terminal diff excerpt:
    +    cursor.execute("DELETE FROM tasks WHERE id = ?", (task_id,))
    +    deleted = cursor.rowcount > 0
    +    conn.commit()
    +    conn.close()
    +    return deleted
    +
    +
     def search_tasks(query):
    
    PostToolUse hook (completed)
    hook context: ! database.py - 1 issue
    [1] line 60 'tempfile.mktemp' is insecure. Use 'tempfile.TemporaryFile' instead  python:S5445
    1 files analyzed - 1 with issues - 1 issue found
    Working (26s • esc to interrupt)
    
    Interface text:
    EXPLORER
    DRYRUN-1
    .agents
    .claude
    .codex
    hooks
    sonar-secrets
    sonar-sqaa
    config.toml
    hooks.json
    .scannerwork
    .sonarlint
    .gitignore
    AGENTS.md
    app.py
    apply-sonar.sh
    config.py
    database.py
    README.md
    sonar-project.proper...
    tasks.py
    OUTLINE
    TIMELINE
    PROBLEMS 1
    OUTPUT
    DEBUG CONSOLE
    TERMINAL
    PORTS
    SONARQUBE 1
    PIXEL AGENTS
    Summarize recent commits
    gpt-5.5 medium · ~/dev/dryrun-1
    SonarQube
    Killian Carlsen-Phelan (4 days ago)
    Ln 53, Col 19
    Spaces: 4
    UTF-8
    LF
    Python
    3.13.13
  2. 39:23

    Editor showing a task deletion function and a terminal warning about an existing temporary-file issue.

    Text in image
    Editor excerpt (clipped):
    database.py
    
    """Database operations for the task manager."""
    
    import sqlite3
    import tempfile
    from config import DATABASE_PATH
    
    def init_db():
        conn = sqlite3.connect(DATABASE_PATH)
        cursor = conn.cursor()
        cursor.execute("""
            CREATE TABLE IF NOT EXISTS tasks (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                title TEXT NOT NULL,
                status TEXT DEFAULT 'open',
                priority INTEGER DEFAULT 0,
                created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
    
    Terminal excerpt:
    not found."
    
    Terminal diff excerpt:
    +def delete_task(task_id):
    +    """Delete a task by ID. Return True if a task was deleted."""
    +    conn = sqlite3.connect(DATABASE_PATH)
    +    cursor = conn.cursor()
    +    cursor.execute("DELETE FROM tasks WHERE id = ?", (task_id,))
    +    deleted = cursor.rowcount > 0
    +    conn.commit()
    +    conn.close()
    +    return deleted
    +
    +
     def search_tasks(query):
    
    PostToolUse hook (completed)
    hook context: ! database.py - 1 issue
    [1] line 60 'tempfile.mktemp' is insecure. Use 'tempfile.TemporaryFile' instead  python:S5445
    1 files analyzed - 1 with issues - 1 issue found
    
    Interface text:
    EXPLORER
    DRYRUN-1
    .agents
    .claude
    .codex
    hooks
    sonar-secrets
    sonar-sqaa
    config.toml
    hooks.json
    .scannerwork
    .sonarlint
    .gitignore
    AGENTS.md
    app.py
    apply-sonar.sh
    config.py
    database.py
    README.md
    sonar-project.proper...
    tasks.py
    OUTLINE
    TIMELINE
    PROBLEMS 1
    OUTPUT
    DEBUG CONSOLE
    TERMINAL
    PORTS
    SONARQUBE 1
    PIXEL AGENTS
    SonarQube
    Killian Carlsen-Phelan (4 days ago)
    Ln 53, Col 19
    Spaces: 4
    UTF-8
    LF
    Python
    3.13.13

Completed task deletion and verification

Codex reports adding parameterized task deletion and passing a syntax check. The Sonar hook still reports an existing, unrelated tempfile.mktemp issue.

Text in image
"""Database operations for the task manager."""

import sqlite3
import tempfile
from config import DATABASE_PATH

def init_db():
    conn = sqlite3.connect(DATABASE_PATH)
    cursor = conn.cursor()
    cursor.execute("""
        CREATE TABLE IF NOT EXISTS tasks (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            title TEXT NOT NULL,
            status TEXT DEFAULT 'open',
            priority INTEGER DEFAULT 0,
            created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP

diff --git a/database.py b/database.py
index [illegible] 100644
+28 lines (ctrl + t to view transcript)
    conn.close()
    return results

Added delete_task(task_id) to database.py:34. It uses a parameterized DELETE FROM tasks WHERE id = ?, commits the change, closes the connection, and returns True only when a row was deleted.

Verification passed: PYTHONPYCACHEPREFIX=/private/tmp/dryrun-pycache python3 -m py_compile database.py.

Note: the Sonar hook still reports the existing unrelated python:S5445 issue for tempfile.mktemp.

Interface text:
dryrun-1
EXPLORER
DRYRUN-1
.agents
.claude
.codex
hooks
sonar-secrets
sonar-sqaa
config.toml
hooks.json
.scannerwork
.sonarlint
.gitignore
AGENTS.md
app.py
apply-sonar.sh
config.py
database.py
README.md
sonar-project.proper...
tasks.py
app.py
database.py 1, M
./apply-sonar.sh Untitled-1
database.py > search_tasks
PROBLEMS 1
OUTPUT
DEBUG CONSOLE
TERMINAL
PORTS
SONARQUBE 1
PIXEL AGENTS
Summarize recent commits
gpt-5.5 medium · ~/dev/dryrun-1
OUTLINE
TIMELINE
main
SonarQube
Killian Carlsen-Phelan (4 days ago)
Ln 53, Col 19
Spaces: 4
UTF-8
LF
Python
3.13.13
Python 3.13.13

39:45Demo milestone

Read the talk

SonarQube + OpenAI: Agentic Development

Killian Carlsen-Phelan wires SonarQube into Codex, traces a SQL injection from command-line input to database execution, and repairs it under an automatic verification hook. The workshop shows where guidance, secret detection and independent analysis enter the coding process—and where their guarantees stop.

From a talk by Killian Carlsen-Phelan

At a glance

Ideas worth remembering

  • A reviewable change needs independent evidence: an agent-generated test can repeat the same misunderstanding as the implementation.

  • The SQL injection connects sys.argv input to an interpolated SQL string and database execution. The repair uses a parameterized query, and reanalysis stops reporting S8702 while retaining a pre-existing issue.

  • Secret interception protects the prompt and tool paths covered by its hooks. The workshop explicitly acknowledges that a bypassed hook may not run.

  • Context augmentation supplies guidance before generation; agentic analysis checks edits afterward. Both require organizational entitlements beyond the free tier.

“Fixed” needs evidence

An agent can produce a plausible fix and a plausible test that share the same mistake. That is the opening problem in the OpenAI/Codex introduction to Killian Carlsen-Phelan’s workshop. Missing context can lead to a local repair that breaks a project-wide requirement; a test generated from that same understanding can then approve the repair. Self-critique helps, but it does not supply an independent check.

“Done” therefore means a reviewable change supported by evidence. The task needs an intended outcome, a defined scope, acceptance criteria and invariants—the properties that must remain true while the implementation changes. Compiler results, tests and analysis should challenge the agent’s claim of completion. Human review remains part of deciding whether the result meets the intent.

Two kinds of control answer different questions:

  • Execution controls: Which tools can the agent use, where can it act, and which actions need approval? A sandbox limits what execution can affect.
  • Artifact checks: Is the resulting code acceptable? Tests, analysis and policy checks examine what the agent produced.

A sandbox can contain a file write without establishing that the SQL query written into that file is safe. These controls need to work together, with people retaining responsibility for intent, exceptions and the decision to ship.

The integration points are concrete. Skills describe procedures; MCP supplies structured tools and context; hooks run checks at particular lifecycle events. Together they can intercept a secret before model input, supply a vulnerability’s location and data path, and recheck a repair. CI and human review still matter, but useful feedback should also arrive while the agent can act on it.

0:131:43
Suggest correction

This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.

0:13 · section reference included

Move verification closer to generation

Killian Carlsen-Phelan, a developer content engineer at Sonar, turns that framing into a workflow for Codex. Sonar’s survey of over a thousand developers supplies the motivation: he reports that 42% of committed code was AI-generated or AI-assisted, 96% of developers did not fully trust it, and fewer than half said they fully verified it before pushing and merging. These are reported survey findings, rather than a measurement of the workshop’s tools. Their practical tension is clear: generation can grow faster than people’s capacity to check it.

Sonar calls its response the agent-centric development cycle. The coding agent handles generation; Sonar supplies three surrounding capabilities:

  • Guide: Give the agent project guidelines, rules and relevant architecture before it writes code. The workshop calls this context augmentation.
  • Verify: Analyze generated changes for security, code quality and maintainability issues. Agentic analysis supplies the automatic check demonstrated later.
  • Solve: Feed detected issues back into the agent’s work so it can repair them and obtain another check.

The timing matters. In the familiar outer loop, a developer writes code, pushes it, waits for CI, discovers a failed test or scan, returns to the IDE and pushes again. The proposed inner loop performs verification in the development environment immediately after generation. That lets the agent respond before a push, reducing the repeated trip through the pipeline. It also addresses the frustration Carlsen-Phelan jokes can add to engineers’ therapy bills.

5:506:31
Suggest correction

This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.

5:50 · section reference included

Start with a small project containing known failures

The hands-on example uses a tiny Python project: about four files and fewer than 200 lines, with four deliberately planted issues. Three are security issues; the fourth is a code smell. A small, known set makes it possible to follow one finding from its initial detection through repair without confusing that repair with a claim that the whole application is clean.

Provisioning starts with Apply Sonar, Carlsen-Phelan’s personal helper script, which he explicitly distinguishes from an official Sonar product. It requires a Bash terminal, creates a SonarQube Cloud project, runs the initial scan and installs supporting tools, including the CLI. The setup authenticates through a browser and asks for the organization associated with the account. Docker is also a workshop prerequisite for the MCP server used later.

The live setup stalls. Wi-Fi is slow, but Carlsen-Phelan also notices that he may have forgotten to export the Sonar token into his shell. He stops sharing his screen while handling the credential, then resumes provisioning. That correction is a useful setup detail: browser authentication and a token available to the shell are separate pieces of the demonstrated process.

14:0637:23
Suggest correction

This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.

11:59 · section reference included

Follow command-line input into SQL execution

The first highlighted failure is an OpenAI API key stored directly in source code. The scan identifies the plaintext credential rather than relying on a reviewer to notice it. Carlsen-Phelan contrasts that with supplying a value through an environment file or variable; the concern is that a credential embedded in code can travel into a published repository.

The SQL injection has a different mechanism. In database.py, a search function inserts its query argument directly into an f-string and passes the resulting SQL text to a cursor for execution. The argument originates in sys.argv, so someone supplying command-line input can influence text that becomes part of the SQL command. Input crosses from being a search value into helping define the query itself.

SonarQube uses symbolic execution and taint analysis to trace that path through the application. The useful distinction is between the source, where user-controlled input enters, and the sink, where the database executes the constructed query. Following the intermediate functions and files connects the dangerous operation to the input that makes it exploitable; inspecting only the final execution line would lose that explanation.

Where does the input travel before it reaches the database? The dashboard’s SQL injection view is the place to inspect that relationship: Carlsen-Phelan follows the source across files and functions to the sink. The completed initial scan reports four issues, including three security issues, and a security rating of E. The data path supplies the actionable detail behind that aggregate rating.

16:2516:55
Suggest correction

This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.

16:25 · section reference included

Install the plugin and separate guidance from analysis

The Codex integration begins by adding the SonarQube plugin marketplace. Inside Codex, /plugins opens the plugin selector; searching for SonarQube allows installation. Carlsen-Phelan then exits Codex so it can reload, authenticates the Sonar CLI with sonar auth login, and runs sonar integrate codex to wire the project into the integration.

The wiring adds a secrets detection hook, an agent Markdown directive to use the SonarQube skills, additional skills and MCP configuration. The token causes another interruption: the exported value appears to be getting lost. Once the setup completes, the integration has both instructions telling Codex how to use SonarQube and configured tools through which it can do so.

Two capabilities sit on opposite sides of an edit:

  • Context augmentation, before work: Fetch relevant project guidelines and architecture and supply them to Codex as it begins a task.
  • Agentic analysis, after an edit: A hook runs when the agent writes or modifies a file and submits the newly written code for server-side analysis.

The first improves the information available for generation. The second checks the resulting change. Carlsen-Phelan’s organization has access to both; free-account participants may not see them.

21:5922:13
Suggest correction

This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.

21:59 · section reference included

Block a fake secret—and examine the hook’s limits

What happens when a prompt itself contains a credential? Carlsen-Phelan starts Codex, accepts the configured hooks and submits a request to push a commit using a fake token supplied for the exercise. The request is immediately blocked. The intended interception point is before the secret reaches model context, rather than after the model has already received it.

Codex reports that the UserPromptSubmit hook blocked the prompt because Sonar detected secrets.Open full source frame
Codex reports that the UserPromptSubmit hook blocked the prompt because Sonar detected secrets.

The distinction becomes sharper in the audience question: could Codex write a script that reads the secret-bearing file instead? Carlsen-Phelan acknowledges that this is possible. The described hook runs at particular prompt or tool-use events; a path that bypasses the relevant event may avoid invoking it. The blocked prompt demonstrates protection on that path, not universal prevention of secret access through arbitrary agent execution.

27:0327:32
Suggest correction

This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.

27:03 · section reference included

Bring dashboard findings into the coding session

The next step gives Codex the project’s existing findings. The SonarQube MCP server lets the session fetch information from SonarQube Cloud, including the issues previously inspected in the dashboard. Carlsen-Phelan restarts the session and server after connectivity trouble, then asks, “List the issues in my project.” That request gives the agent a specific analysis result to work from.

An audience question separates the local pieces. The CLI provisions and configures the integration; the MCP server runs in Docker. Carlsen-Phelan further clarifies that task execution may use an MCP skill or a CLI command. The plugin sits on top of these facilities, so the setup should not be read as every operation passing through one mandatory CLI-to-MCP chain.

The session finds the issue-listing and context-augmentation skills. Secret scanning also runs while it reads files, including its own skill files. Eventually, the same findings shown in the dashboard become available in the terminal. The workshop’s long waits make connectivity a visible dependency; Carlsen-Phelan’s expectation of much faster operation on normal Wi-Fi is personal experience, not a latency benchmark established by this run.

Access also affects which workflow a participant can reproduce. Carlsen-Phelan describes the integration as available across SonarQube Cloud, Server, enterprise and free-tier use. Context augmentation and agentic analysis require the corresponding organizational entitlements and are unavailable on the free tier. Retrieving findings and automatically analyzing every edit are therefore separate capabilities.

28:4329:00
Suggest correction

This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.

28:43 · section reference included

Replace interpolation with a parameterized query

The selected finding is S8702, which Carlsen-Phelan describes as a rule written for AI agentic workflows. In this project it identifies the previously traced sys.argv path into SQL execution. The instruction to Codex is short: fix S8702. Its specificity comes from the issue already retrieved into the session, connecting the request to the vulnerable operation.

Codex replaces the vulnerable construction with a parameterized query. The important change is the separation of SQL structure from the supplied value: the search argument is bound as data instead of being interpolated into executable SQL text. After the edit, the post-tool-use hook sends the change for server-side analysis. This addresses the “hydra” problem Carlsen-Phelan describes—fixing one issue only to introduce several more.

What changed in the query, and what does the recheck actually clear? The reported result is that S8702 disappears and the edited code passes the inline analysis. Another planted issue remains in the file and is identified as pre-existing. That distinction keeps the repair scoped: resolving the selected injection does not require silently fixing every unrelated issue, and a successful recheck does not declare the entire file free of problems.

Without agentic analysis, the code can still be scanned during a subsequent CI push, provided that scan is configured. What the hook changes is when the result becomes available: the agent gets analysis feedback immediately after its edit and can respond in the same session. Consistent with the opening, this is evidence from a particular checker; it complements behavioral tests and human review.

34:4535:15
Suggest correction

This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.

35:15 · section reference included

Use the same checks when adding new behavior

The final demonstration moves from repairing a known vulnerability to generating a new operation: delete a task by ID in database.py. Context augmentation fetches relevant project rules and architecture for Codex before implementation. The feature completes quickly in the session, and agentic analysis checks the generated change.

The feedback now applies to new work as well as old findings. If analysis flags an issue, the intended behavior is for Codex to continue repairing it and receive another check. The recording describes that conditional path; it does not show a newly detected failure during this final operation. The demonstrated progression is guidance into generation, followed by analysis of the resulting code, all within the terminal.

The remaining planted issues provide further exercises, and participants whose organizations have the entitlements can explore context augmentation and agentic analysis. Carlsen-Phelan closes by directing people who get stuck to the Sonar community, where product engineers answer questions. The useful stopping point is concrete: a blocked fake credential, a retrieved and repaired SQL injection, and a new database operation checked during development—with the hook’s bypass limits and the organization’s feature access still part of the design.

38:1938:49
Suggest correction

This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.

38:19 · section reference included

Resources

Read the complete timestamped transcript

5 slide groups · 26 demo milestones. Extracted from the recording; expand builds to follow changes. Timestamps are approximate. 1 additional group was omitted from this pass.

  1. 0:13

    Cool. Uh, so I'm here from, uh, Codex's deployment engineering team, and I want to quickly say a few things to introduce the amazing folks at Sonar, as well as Killian. Uh, so I'm gonna skip some of the agent basics that I typically talk about because I get the feeling that this audience knows what they're doing when it comes into that. We're gonna dive right into the harder questions like: What does it mean for an agent to have completed a task? What are trust boundaries? And we have three kinda spicy claims that we want to present as well. Uh,

  2. 0:43

    one is done means a task is completed with evidence. Two is that containment is not correctness. And three is that the feedback contract belongs inside the loop. So when we have an agent loop, that tends to follow a few predictable patterns. We tend to have this model action, uh, we have the execution that is governed by the model, we observe the changes, whether that be logs or results, output, or otherwise, and we continue updating the plan. That's sort of like the overarching agent loop that we follow. And then

  3. 1:13

    with each individual task, we have, uh, an outcome, we have invariants, we have a generally defined scope for what we're working on, and of course, we also have acceptance criteria as well. Uh, so the definition of done for us, typically it's a reviewable diff, some tool evidence, that type of thing. It doesn't mean just saying fixed. It actually means saying fixed and providing the evidence supporting this fact. Uh, so cheaper implementations tend to shift the bottleneck to specification

  4. Workshop resources

    Scan the QR code or visit the workshop repository to follow along. Killian notes that there are a few prerequisites.

    Text in image
    https://github.com/sonar-samples/learn-codex-workshop
    
    Sonar
  5. 1:43

    and verification, and that's really not what we're wanting to do. Um, there's this idea of correlated failure as well, and there's typically a couple of common failure modes that coding agents, uh, tend to fall into. It tends to fall back to incomplete context, uh, where... Or maybe there's a local fix that violates some global invariants that we have. Uh, or better yet, the, the generated test that we actually do to verify results in the same issues just being propagated

  6. 2:13

    through. Uh, so self-critique is useful, but it's not an independent oracle, and we often tend to find that some of the results of the agent and the verifier tend to be orthogonal to each other. You can't, uh, determine whether a task is done without looking at both parts of it. Uh, so you, you typically want to almost seek out disconfirming evidence of a task being completed. Uh, according to the compiler, is it done? According to the tests, analysis, so on and so forth, is it done? And it's--

  7. Workshop resources

    Scan the QR code or visit the workshop repository to follow along. Killian notes that there are a few prerequisites.

    Text in image
    https://github.com/sonar-samples/learn-codex-workshop
    
    Sonar
  8. 2:43

    You can't really replace human review in the entire cycle as well. Um, the, the next point I wanted to quickly hit on is, uh, containment doesn't equal correctness. Uh, we have the execution layer, which typically defines what an agent can do, right? What tools does it, does it have access to? Uh, what scope does it have, uh, purview over? What approvals does it need to act? And then we have the, uh, with this execution layer, we have the artifact layer. Uh, and this is really where the results are

  9. 3:13

    evaluated. Uh, is the result acceptable? Uh, what tests were produced? What analyses? What policy? Even what intent is there? Uh, so a sandbox can contain a write, but it can't prove that a query is safe. Uh, so what I'm trying to get at is that no oracle is proof, and that you want to layer controls with different boundaries. Sort of this defense in depth, uh, these multi layers of guardrails. That's sort of the overall

  10. Workshop resources

    Scan the QR code or visit the workshop repository to follow along. Killian notes that there are a few prerequisites.

    Text in image
    https://github.com/sonar-samples/learn-codex-workshop
    
    Sonar
  11. 3:43

    idea. And the great part about that is that you as a human, you own the intent, you own the exceptions, and of course, you own the decision whether to ship it or not. Uh, so this is one last thing. Uh, there's a feedback contract that we tend to advise as well. Uh, typically, those come with skills, um, which of course are procedures as to how to accomplish a particular task. Uh, MCPs contain structured tools and context. And of course, we are able to provide

  12. 4:12

    lifecycle checks with hooks. Really good for finding out if you have hard-coded secrets or that kind of thing as well. Uh, so with this, you want to create this full CI and human review process. That should ultimately be the core of what the human's role is within this. Uh, and that sort of... So anyways, um, what you want to evaluate when you are creating this sort of agentic process is a few things. Uh, what's the boundary, for example? Uh, are you able to, uh,

  13. Workshop resources

    Scan the QR code or visit the workshop repository to follow along. Killian notes that there are a few prerequisites.

    Text in image
    https://github.com/sonar-samples/learn-codex-workshop
    
    Sonar
  14. 4:42

    intercept secrets before model input, for example? Uh, how is the project grounded? Uh, do you have any concrete rules or locations or vulnerability paths that you are able to provide? Uh, what is the scope? Are parameters binding while preserving behavior? These are things to check for. And of course, you have to constantly run your rechecks, uh, assert that the agents are not the terminal state. Uh, so anyways, uh, enough yapping from my end of

  15. 5:12

    things. Uh, if there's, uh, three points that you take away from me, it's that done means a task is complete with evidence. Two is that containment is not correctness. And three is that the feedback contract belongs inside the loop, so that you can fully take advantage of the capabilities that your agents, such as Codex, provide. Uh, so Killian, let's, uh, let's make that loop con- uh, complete, why don't we? That's, uh, about all from my end of things, so thank you so much for, uh, let- giving me the

  16. Workshop resources

    Scan the QR code or visit the workshop repository to follow along. Killian notes that there are a few prerequisites.

    Text in image
    https://github.com/sonar-samples/learn-codex-workshop
    
    Sonar
  17. 5:42

    opportunity to give this introduction.

  18. 5:45

    Thanks for coming.

  19. 5:46

    Thank you.

  20. 5:50

    If you can take a look at this, then, um, and, and scan it and follow through, that would be very helpful. There are a few prerequisites. Um, again, I am Killian I am a developer content engineer at Sonar. Um, so thank you very much again, um, OpenAI and Tony for giving us a little intro into all of this. Um, Codex is a very powerful tool. I use it all the time. I found it very helpful. It's has a fast CLI, it has a, a pretty

  21. Workshop resources

    Scan the QR code or visit the workshop repository to follow along. Killian notes that there are a few prerequisites.

    Text in image
    https://github.com/sonar-samples/learn-codex-workshop
    
    Sonar
  22. 6:20

    smart sandbox system, and the hook system that it has as well integrates really well with tools like SonarQube, like I'd like to hop into today.

  23. Wiring Your Team for Agentic Development

    Killian Carlsen-Phelan introduces the session with a question: how can teams verify that code and other output generated by agents like Codex are safe?

    Text in image
    Wiring Your Team for Agentic Development with SonarQube & OpenAI
    
    Killian Carlsen-Phelan | Developer Content Engineer
    
    Sonar
  24. 6:31

    So wiring your team for agentic development with SonarQube and OpenAI. Um, the question I wanna pose today is: how do we make sure that the code and the output generated by agents like Codex is verified, that it's safe? At Sonar we had this idea of the agent-centric development cycle. We did, um, some, some research in the past year or so, and we surveyed over a thousand

  25. Agent Centric Development Cycle

    Sonar introduces a cycle around agent-generated code. Carlsen-Phelan frames verification as the new bottleneck as agents generate more code.

    Text in image
    Introducing the
    Agent Centric Development Cycle
    
    The Sonar methodology for ensuring AI agents are operating in a trustworthy, consistent, and transparent way.
    
    Agent Centric Development Cycle
    GUIDE
    VERIFY
    SOLVE
    GENERATE
    AC/DC
    Sonar
  26. Agent Centric Development Cycle

    Sonar introduces a cycle around agent-generated code. Carlsen-Phelan frames verification as the new bottleneck as agents generate more code.

    Text in image
    Introducing the
    Agent Centric Development Cycle
    
    The Sonar methodology for ensuring AI agents are operating in a trustworthy, consistent, and transparent way.
    
    Agent Centric Development Cycle
    GUIDE
    VERIFY
    SOLVE
    GENERATE
    AC/DC
    Sonar
  27. 7:01

    developers, and we found that, uh, forty-two percent of committed code is either AI-generated or AI-assisted, but ninety-six percent of developers do not fully trust it, right? So the vast majority of people do not just think, "Hey, this is safe," right off the bat. Less than half of them say that they fully verify the code before they push and merge it into the code base. There's a bit of tension there. No one trusts it. A bunch of

  28. 7:30

    untru-untrusted code is getting into the code base. Um, the reason being is the, the bottleneck used to be code generation, right? How can we create what we're, what we're trying to do to achieve the desired outcome? How do we actually write the code for an application that we're trying to build? Um, with AI agents, that has for the most pa-part been solved with them either doing it themselves or with the assistance of, of AI agents. So the bottleneck has shifted

  29. Agent Centric Development Cycle

    Sonar introduces a cycle around agent-generated code. Carlsen-Phelan frames verification as the new bottleneck as agents generate more code.

    Text in image
    Introducing the
    Agent Centric Development Cycle
    
    The Sonar methodology for ensuring AI agents are operating in a trustworthy, consistent, and transparent way.
    
    Agent Centric Development Cycle
    GUIDE
    VERIFY
    SOLVE
    GENERATE
    AC/DC
    Sonar
  30. 8:00

    now from just code generation to code verification, right? We have a massive amount of code being generated, but now it is up to the human limitation of, "Hey, how do I make sure that this is safe? What help and what tools can I get to verify that this is not gonna nuke my code base or nuke my customers and create all sorts of bad, uh, issues going on?" So we have, uh, four steps in the ACDC, the agent-centric development cycle.

  31. The three key stages of the AC/DC

    Guide supplies context and constraints; Verify checks generated code; Solve fixes issues and feeds lessons back into Guide. The diagram places these stages in a loop around Generate.

    Text in image
    The three key stages of the AC/DC
    
    Guide
    DEFINE CONTEXT AND CONSTRAINTS
    Provide agents with guardrails and the most relevant context, standards, and architectural constraints so output fits the organization’s requirements.
    
    Guide
    Generate
    Solve
    Verify
    
    Verify
    REVIEW AND VALIDATE CODE
    Mandatory multi-layer verification with deterministic evaluation, logical AI reasoning, and runtime validation in a sandbox to ensure quality, security, compliance, and functionality.
    
    Solve
    FIX ISSUES
    Automated debugging and remediation based on verification feedback. Issues are fixed, and lessons feed back into the Guide phase.
    
    Confidential - ©2026, SonarSource Sàrl
    4
  32. 8:30

    One of them is not necessarily from Sonar. That is generate. That is whatever coding tool you're using, Codex, anything else, um, that is the generate step. But Sonar owns guide, verify, and solve. What guide is, is we inject the agent with proper context, and that includes your project guidelines, any rules, any specific architecture to make sure that it has high quality context before it even starts building anything. We found that this

  33. The three key stages of the AC/DC

    Guide supplies context and constraints; Verify checks generated code; Solve fixes issues and feeds lessons back into Guide. The diagram places these stages in a loop around Generate.

    Text in image
    The three key stages of the AC/DC
    
    Guide
    DEFINE CONTEXT AND CONSTRAINTS
    Provide agents with guardrails and the most relevant context, standards, and architectural constraints so output fits the organization’s requirements.
    
    Guide
    Generate
    Solve
    Verify
    
    Verify
    REVIEW AND VALIDATE CODE
    Mandatory multi-layer verification with deterministic evaluation, logical AI reasoning, and runtime validation in a sandbox to ensure quality, security, compliance, and functionality.
    
    Solve
    FIX ISSUES
    Automated debugging and remediation based on verification feedback. Issues are fixed, and lessons feed back into the Guide phase.
    
    Confidential - ©2026, SonarSource Sàrl
    4
  34. 9:00

    reduces token cost overall, and at enterprise scale, that, I mean, saves a lot of money in the long term. Verify is as soon as it's done creating, uh, whatever task you've assigned to a generated code, we wanna make sure that no issues are being introduced. So no security issues, code quality issues, maintainability, anything like that, none of that needs to be pushed out to production code. And then solve is, okay, we have detected there's an issue, right? There's some sort of

  35. 9:29

    injection vulnerability or whatever that's going on. We need to remediate that quickly, um, and ef-as efficiently as possible so that we can kinda have this iterative coding system right there. And the last slide I'm gonna show before we hop into the actual activity is, uh, the concept of the inner loop and the outer loop of verification. Outer loop is your traditional CI system that you have set up, right? So you write code, you push it to

  36. The inner loop and the outer loop

    The inner loop guides, verifies and fixes code during agent reasoning in the IDE. The outer loop runs broader checks after the agent finishes, as in a CI pipeline that can send developers back to fix failures.

    Text in image
    The inner loop and the outer loop
    
    The inner loop:
    Guide-Verify-Solve happens in each agentic reasoning loop, ensuring that the agent stays on track as it methodically works to achieve the plans.
    
    Guide
    Generate
    Solve
    Verify
    
    The outer loop:
    Guide-Verify-Solve happens once the agent has ‘finished’ its work. Here, more comprehensive verification occurs and, often, the agent will have to fix larger-scale issues that are identified.
    
    Confidential - ©2026, SonarSource Sàrl
    5
  37. The inner loop and the outer loop

    The inner loop guides, verifies and fixes code during agent reasoning in the IDE. The outer loop runs broader checks after the agent finishes, as in a CI pipeline that can send developers back to fix failures.

    Text in image
    The inner loop and the outer loop
    
    The inner loop:
    Guide-Verify-Solve happens in each agentic reasoning loop, ensuring that the agent stays on track as it methodically works to achieve the plans.
    
    Guide
    Generate
    Solve
    Verify
    
    The outer loop:
    Guide-Verify-Solve happens once the agent has ‘finished’ its work. Here, more comprehensive verification occurs and, often, the agent will have to fix larger-scale issues that are identified.
    
    Confidential - ©2026, SonarSource Sàrl
    5
  38. 9:59

    GitHub, GitLab, whatever you use. The pipeline runs, and something may fail, right? Your test or a scan or SonarQube may fail, and then you go back to the IDE, and then you try and fix it, and then you push it, and then it fails again. This has been the bane of my existence, the bane of many developers' existences. So we wanna save time by shifting left to the inner loop, and that's the IDE. So that's as soon as we are done generating code, we wanna

  39. 10:29

    verify that it is correct within the IDE without having to push it out. Um, this saves a lot of time. Uh, I mean, especially, you know, being able to automatically verify all this stuff. Time is money at, at enterprises, and your engineers save a lot of money on therapy bills as well without that frustration. Um, all right. That is the last slide I really wanna focus on, uh, before hopping into

  40. The inner loop and the outer loop

    The inner loop guides, verifies and fixes code during agent reasoning in the IDE. The outer loop runs broader checks after the agent finishes, as in a CI pipeline that can send developers back to fix failures.

    Text in image
    The inner loop and the outer loop
    
    The inner loop:
    Guide-Verify-Solve happens in each agentic reasoning loop, ensuring that the agent stays on track as it methodically works to achieve the plans.
    
    Guide
    Generate
    Solve
    Verify
    
    The outer loop:
    Guide-Verify-Solve happens once the agent has ‘finished’ its work. Here, more comprehensive verification occurs and, often, the agent will have to fix larger-scale issues that are identified.
    
    Confidential - ©2026, SonarSource Sàrl
    5
  41. 10:59

    the terminal. Uh, a few quick things I wanna touch base on. Before that, you're gonna see two ti-- uh, two tools that I'm gonna talk about. Our tool for context, uh, our tool called context augmentation, it's what we're gonna use for the guide stage, and our tool for agentic analysis you're gonna see in the verify stage. We'll come back to those later. Um, and the, the big takeaway as well that I want everyone to keep focusing on is this bottleneck has shifted from code generation to

  42. 11:29

    code verification. Um, before we hop in as well, everyone should have Docker running if you're able to on your computer. And just quick show of thumbs, just so I have an idea of people who have been able to follow along with the prerequisites so far. Thumbs up if you got Docker running and are kinda primed, ready to go hop into the terminal and follow along. Awesome. A few. Perfect. Thank you. Um, if not, again, this repo is available. You can follow through with

  43. The inner loop and the outer loop

    The inner loop guides, verifies and fixes code during agent reasoning in the IDE. The outer loop runs broader checks after the agent finishes, as in a CI pipeline that can send developers back to fix failures.

    Text in image
    The inner loop and the outer loop
    
    The inner loop:
    Guide-Verify-Solve happens in each agentic reasoning loop, ensuring that the agent stays on track as it methodically works to achieve the plans.
    
    Guide
    Generate
    Solve
    Verify
    
    The outer loop:
    Guide-Verify-Solve happens once the agent has ‘finished’ its work. Here, more comprehensive verification occurs and, often, the agent will have to fix larger-scale issues that are identified.
    
    Confidential - ©2026, SonarSource Sàrl
    5
  44. 11:59

    this on your own time. Um, you, you will have all of this information. So let me pop out of this real quick. I only have limited view, cutting the top part of my screen off, but should be good to go. All right. So the first thing that we are going to do is we are going to run this script called Apply Sonar. Um, this is just the, the repo that I clone locally. This is gonna require a bash terminal, so if you're on Windows, you can use Git Bash or something like that. Um,

  45. SonarQube Cloud setup

    Carlsen-Phelan runs his personal Apply Sonar script, then authorizes the connection in a browser. The success page says the token was sent to the terminal to finish setup.

    Text in image
    def search_tasks(query):
        """Search tasks by title."""
        conn = sqlite3.connect(DATABASE_PATH)
        cursor = conn.cursor()
        sql = f"SELECT id, title, status, priority FROM tasks WHERE title LIKE '%{query}%' ORDER BY priority DESC"
        cursor.execute(sql)
        results = cursor.fetchall()
        conn.close()
        return results
    
    def export_tasks(status_filter):
        """Export filtered tasks to a CSV file."""
        filename = tempfile.mktemp(suffix=".csv")
    
        conn = sqlite3.connect(DATABASE_PATH)
        cursor = conn.cursor()
        cursor.execute("SELECT * FROM tasks WHERE status = ?", (status_filter,))
        tasks = cursor.fetchall()
    
    Terminal:
    dryrun-1 on main via v3.9.6
    ./apply-sonar.sh
    
    Interface text:
    EXPLORER
    DRYRUN-1
    .claude
    .gitignore
    app.py
    apply-sonar.sh
    config.py
    database.py
    README.md
    tasks.py
    PROBLEMS 1
    OUTPUT
    DEBUG CONSOLE
    TERMINAL
    PORTS
    SONARQUBE 1
    PIXEL AGENTS
    OUTLINE
    TIMELINE

    12:08Demo milestone

  46. 12:29

    so I'm gonna go ahead and type that in, that is apply sonar.

  47. 12:38

    All right, and this is going to do a few things. This is a personal tool that I built. It is not an official Sonar product. Um, it is just a shortcut so we're not spending ten minutes clicking through a UI or anything like that. Let me make sure my Wi-Fi is doing all right. Okay.

  48. SonarQube Cloud setup

    Carlsen-Phelan runs his personal Apply Sonar script, then authorizes the connection in a browser. The success page says the token was sent to the terminal to finish setup.

    Text in image
    def search_tasks(query):
        """Search tasks by title."""
        conn = sqlite3.connect(DATABASE_PATH)
        cursor = conn.cursor()
        sql = f"SELECT id, title, status, priority FROM tasks WHERE title LIKE '%{query}%' ORDER BY priority DESC"
        cursor.execute(sql)
        results = cursor.fetchall()
        conn.close()
        return results
    
    def export_tasks(status_filter):
        """Export filtered tasks to a CSV file."""
        filename = tempfile.mktemp(suffix=".csv")
    
        conn = sqlite3.connect(DATABASE_PATH)
        cursor = conn.cursor()
        cursor.execute("SELECT * FROM tasks WHERE status = ?", (status_filter,))
        tasks = cursor.fetchall()
    
    Terminal:
    dryrun-1 on main via v3.9.6
    ./apply-sonar.sh
    
    Interface text:
    EXPLORER
    DRYRUN-1
    .claude
    .gitignore
    app.py
    apply-sonar.sh
    config.py
    database.py
    README.md
    tasks.py
    PROBLEMS 1
    OUTPUT
    DEBUG CONSOLE
    TERMINAL
    PORTS
    SONARQUBE 1
    PIXEL AGENTS
    OUTLINE
    TIMELINE

    12:50Demo milestone

  49. 13:00

    Running through a little bit of computer slowness up here. Um, but it'll-- this will create a SonarQube Cloud project for you, um, runs the first scan for you.

  50. 13:12

    Okay. EU. And it will auth me in. So we just pop open the browser. Um, this will install a few related SonarQube tools for you, like our CLI and anything else that we're gonna need to run our plugin with Codex on top of.

  51. SonarQube Cloud setup

    Carlsen-Phelan runs his personal Apply Sonar script, then authorizes the connection in a browser. The success page says the token was sent to the terminal to finish setup.

    Text in image
    Connection successful!
    
    Your user token has now been generated & sent to your terminal.
    
    Return to your terminal to complete the setup.
    
    Interface text:
    SonarQube Cloud
    Authorize SonarQube CLI?
    sonarcloud.io/auth?product=cli&port=64124

    13:34Demo milestone

  52. 13:36

    All right.

  53. 13:38

    Bear with me as it looks like I'm bumping into just a little bit of Wi-Fi slowness in here, but it shouldn't be a big issue. So that has been successful.

  54. Select an organization

    After SonarQube Cloud returns a token, the terminal asks which organization to use. The presenter says to choose the organization created with the account.

    Text in image
    def search_tasks(query):
        """Search tasks by title."""
        conn = sqlite3.connect(DATABASE_PATH)
        cursor = conn.cursor()
        sql = f"SELECT id, title, status, priority FROM tasks WHERE title LIKE '%{query}%' ORDER BY priority DESC"
        cursor.execute(sql)
        results = cursor.fetchall()
        conn.close()
        return results
    
    def export_tasks(status_filter):
        """Export filtered tasks to a CSV file."""
        filename = tempfile.mktemp(suffix=".csv")
    
        conn = sqlite3.connect(DATABASE_PATH)
        cursor = conn.cursor()
        cursor.execute("SELECT * FROM tasks WHERE status = ?", (status_filter,))
        tasks = cursor.fetchall()
    
    Terminal:
    ./apply-sonar.sh
    Where would you like to connect? SonarQube Cloud
    Which SonarQube Cloud region? EU (sonarcloud.io)
    Authenticating with: https://sonarcloud.io
    Obtaining access token from SonarQube...
    URL: https://sonarcloud.io/auth?product=cli&port=64124
    Press Enter to open the browser
    Waiting for authorization... or paste token and press Enter:
    Token received
    Select an organization
    Sonar-Gitar-Demos (sonar-gitar-demos)
    kcarlsen-sonarsource (kcarlsen-sonarsource)
    Enter organization key manually
    
    Interface text:
    DRYRUN-1
    EXPLORER
    .claude
    .gitignore
    app.py
    apply-sonar.sh
    config.py
    database.py
    README.md
    tasks.py
    PROBLEMS 1
    OUTPUT
    DEBUG CONSOLE
    TERMINAL
    PORTS
    SONARQUBE 1
    PIXEL AGENTS
    OUTLINE
    TIMELINE

    13:46Demo milestone

  55. 13:51

    Um, you're gonna wanna put in, um, the org that you want, so the org that you were created, that was, uh, created for you when you made an account.

  56. 14:06

    And that'll run. Um, this right here, just to talk about the project, this is a tiny Python project. Nothing complicated. There's like four files, less than two hundred lines total, and I have planted four vulnerabilities in there. Three of them are security vulnerabilities, and one of them is a code smell. And, um, when this script gets done running, then we're gonna hop into the dashboard and make sure that, uh, we can see stuff up there.

  57. 14:37

    All right.

  58. 14:39

    Normally, uh, I think there's a lot of people trying to access this Wi-Fi. Uh, I've not seen this take longer than a minute on my own personal Wi-Fi. So if you're following along at home, don't think you'll have to be sitting around like this, um, for a little while. Whoops.

  59. Select an organization

    After SonarQube Cloud returns a token, the terminal asks which organization to use. The presenter says to choose the organization created with the account.

    Text in image
    def search_tasks(query):
        """Search tasks by title."""
        conn = sqlite3.connect(DATABASE_PATH)
        cursor = conn.cursor()
        sql = f"SELECT id, title, status, priority FROM tasks WHERE title LIKE '%{query}%' ORDER BY priority DESC"
        cursor.execute(sql)
        results = cursor.fetchall()
        conn.close()
        return results
    
    def export_tasks(status_filter):
        """Export filtered tasks to a CSV file."""
        filename = tempfile.mktemp(suffix=".csv")
    
        conn = sqlite3.connect(DATABASE_PATH)
        cursor = conn.cursor()
        cursor.execute("SELECT * FROM tasks WHERE status = ?", (status_filter,))
        tasks = cursor.fetchall()
    
    Terminal:
    ./apply-sonar.sh
    Where would you like to connect? SonarQube Cloud
    Which SonarQube Cloud region? EU (sonarcloud.io)
    Authenticating with: https://sonarcloud.io
    Obtaining access token from SonarQube...
    URL: https://sonarcloud.io/auth?product=cli&port=64124
    Press Enter to open the browser
    Waiting for authorization... or paste token and press Enter:
    Token received
    Select an organization
    Sonar-Gitar-Demos (sonar-gitar-demos)
    kcarlsen-sonarsource (kcarlsen-sonarsource)
    Enter organization key manually
    
    Interface text:
    DRYRUN-1
    EXPLORER
    .claude
    .gitignore
    app.py
    apply-sonar.sh
    config.py
    database.py
    README.md
    tasks.py
    PROBLEMS 1
    OUTPUT
    DEBUG CONSOLE
    TERMINAL
    PORTS
    SONARQUBE 1
    PIXEL AGENTS
    OUTLINE
    TIMELINE

    14:51Demo milestone

  60. 15:01

    So I am... You know what? I may have actually forgot to export my token, which is a step in the repo real quick. So, um, this should be in your shell. I'm gonna pull out, my disconnect real quick just for a second so I don't expose my Sonar token to a room full of a bunch of people, and then I'll pop right back in.

  61. 15:27

    Uh, so there should be some steps in the, the repository. You will navigate through the dashboard. I think it's under administration within SonarQube Cloud.

  62. 15:48

    All right, re-mirror.

  63. SonarQube Cloud setup

    Carlsen-Phelan runs his personal Apply Sonar script, then authorizes the connection in a browser. The success page says the token was sent to the terminal to finish setup.

    Text in image
    def search_tasks(query):
        """Search tasks by title."""
        conn = sqlite3.connect(DATABASE_PATH)
        cursor = conn.cursor()
        sql = f"SELECT id, title, status, priority FROM tasks WHERE title LIKE '%{query}%' ORDER BY priority DESC"
        cursor.execute(sql)
        results = cursor.fetchall()
        conn.close()
        return results
    
    def export_tasks(status_filter):
        """Export filtered tasks to a CSV file."""
        filename = tempfile.mktemp(suffix=".csv")
    
        conn = sqlite3.connect(DATABASE_PATH)
        cursor = conn.cursor()
        cursor.execute("SELECT * FROM tasks WHERE status = ?", (status_filter,))
        tasks = cursor.fetchall()
    
    Terminal:
    dryrun-1 on main via v3.9.6
    ./apply-sonar.sh
    
    Interface text:
    EXPLORER
    DRYRUN-1
    .claude
    .gitignore
    app.py
    apply-sonar.sh
    config.py
    database.py
    README.md
    tasks.py
    PROBLEMS 1
    OUTPUT
    DEBUG CONSOLE
    TERMINAL
    PORTS
    SONARQUBE 1
    PIXEL AGENTS
    OUTLINE
    TIMELINE

    15:51Demo milestone

  64. 15:55

    All right. So this will run. Um, a few things I wanna talk about as well. So we are going to see a, uh, SQL injection issue that pops in. Okay, awesome. This looks like it's working now. Um, so it'll go through, and it'll automatically create, um, everything for me in the dashboard. The security rating that it will come up with is going to be E. This is the very lowest. We have, uh, baked in some security issues, and, uh,

  65. SonarQube project setup and analysis

    The setup script creates the SonarQube project and starts analysis. While it runs, the demo shows a search command passing user input into an SQL f-string, which the speaker identifies as a SQL injection vulnerability.

    Text in image
    def search_tasks(query):
        """Search tasks by title."""
        conn = sqlite3.connect(DATABASE_PATH)
        cursor = conn.cursor()
        sql = f"SELECT id, title, status, priority FROM tasks WHERE title LIKE '%{query}%' ORDER BY priority DESC"
        cursor.execute(sql)
        results = cursor.fetchall()
        conn.close()
        return results
    
    def export_tasks(status_filter):
        """Export filtered tasks to a CSV file."""
        filename = tempfile.mktemp(suffix=".csv")
    
        conn = sqlite3.connect(DATABASE_PATH)
        cursor = conn.cursor()
        cursor.execute("SELECT * FROM tasks WHERE status = ?", (status_filter,))
        tasks = cursor.fetchall()
    
    Terminal:
    > ./apply-sonar.sh
    [OK] Already authenticated with SonarQube Cloud.
    [INFO] Detected project configuration:
        Organization: kcarlsen-sonarsource
        Project key: kcarlsen-sonarsource_learn-codex-workshop
        Project name: learn-codex-workshop
    
    Interface text:
    EXPLORER
    DRYRUN-1
    .claude
    .gitignore
    app.py
    apply-sonar.sh
    config.py
    database.py
    README.md
    tasks.py
    PROBLEMS 1
    OUTPUT
    DEBUG CONSOLE
    TERMINAL
    PORTS
    SONARQUBE 1
    PIXEL AGENTS

    15:56Demo milestone

  66. 16:25

    SonarQube immediately detects these and says, "Hey, this is no good." The next thing that I'm gonna dig into as soon as this gets loaded is just walk through a couple issues. One of them is going to be an open AP-- uh, OpenAI API key. Very relevant if people are using Codex. I have done this. It's actually right here in the code base. Oops, someone forgot to use an ENV file or pass this in as a variable. Um, this happens all

  67. 16:55

    the time. And what a lot of times what happens is people accidentally push these into production code. Um, and the average remediation time for a secret in a public repository is ninety days right now. That is crazy. That is... Your, your token is just sitting out there for all the world to see, all the bots to scrape for ninety days. We want to prevent this as much as possible, and we have a couple tools for that here. Um, another issue that I'm gonna highlight for y'all

  68. 17:26

    here in a second is there is a SQL injection vulnerability. Um, and if anyone who is just perusing through this code as a security was, you may have noticed it. But, um, right here in this database.py file, I am passing in, um, a query from here directly into an f-string that is being, uh, cursor executed. So the argument is going straight into the

  69. SonarQube project setup and analysis

    The setup script creates the SonarQube project and starts analysis. While it runs, the demo shows a search command passing user input into an SQL f-string, which the speaker identifies as a SQL injection vulnerability.

    Text in image
    def main():
        [lines 30–44 not visible]
            title = sys.argv[2]
            priority = int(sys.argv[3]) if len(sys.argv) > 3 else 0
            add_task(title, priority)
            print(f"Task added: {title}")
    
        elif command == "search":
            if len(sys.argv) < 3:
                print("Usage: python app.py search <query>")
                sys.exit(1)
            results = search_tasks(sys.argv[2])
            print_tasks(results)
    
        elif command == "update":
            handle_update()
    
        elif command == "export":
            status = sys.argv[2] if len(sys.argv) > 2 else "open"
            path = export_tasks(status)
            print(f"Exported to {path}")
    
    Terminal:
    > ./apply-sonar.sh
    [OK] Already authenticated with SonarQube Cloud.
    [INFO] Detected project configuration:
        Organization: kcarlsen-sonarsource
        Project key: kcarlsen-sonarsource_learn-codex-workshop
        Project name: learn-codex-workshop
    [OK] Project created: kcarlsen-sonarsource_learn-codex-workshop
    [OK] New code definition set to 'previous version'.
    [OK] sonar-project.properties created.
    [OK] .sonarlint/connectedMode.json created.
    [OK] sonar-scanner ready.
    [INFO] Running SonarQube analysis... (this may take a few minutes)
    
    Interface text:
    EXPLORER
    DRYRUN-1
    .claude
    .scannerwork
    .sonarlint
    .gitignore
    app.py
    apply-sonar.sh
    config.py
    database.py
    README.md
    sonar-project.proper...
    tasks.py
    PROBLEMS 1
    OUTPUT
    DEBUG CONSOLE
    TERMINAL
    PORTS
    SONARQUBE 1
    PIXEL AGENTS

    17:27Demo milestone

  70. Search query construction

    search_tasks inserts a command-line query into an SQL f-string and executes it, creating the SQL injection vulnerability the speaker highlights while SonarQube analysis runs.

    Text in image
    database.py
    
    def add_task(title, priority=0):
        [lines 25–27 not visible]
        "INSERT INTO tasks (title, priority) VALUES (?, ?)", (title, priority)
        )
        conn.commit()
        conn.close()
    
    def search_tasks(query):
        """Search tasks by title."""
        conn = sqlite3.connect(DATABASE_PATH)
        cursor = conn.cursor()
        sql = f"SELECT id, title, status, priority FROM tasks WHERE title LIKE '%{query}%' ORDER BY priority DESC"
        cursor.execute(sql)
        results = cursor.fetchall()
        conn.close()
        return results
    
    def export_tasks(status_filter):
        """Export filtered tasks to a CSV file."""
        filename = [illegible]
    
    Terminal:
    > ./apply-sonar.sh
    [OK] Already authenticated with SonarQube Cloud.
    [INFO] Detected project configuration:
        Organization: kcarlsen-sonarsource
        Project key: kcarlsen-sonarsource_learn-codex-workshop
        Project name: learn-codex-workshop
    [OK] Project created: kcarlsen-sonarsource_learn-codex-workshop
    [OK] New code definition set to 'previous version'.
    [OK] sonar-project.properties Created.
    [OK] .sonarlint/connectedMode.json Created.
    [OK] sonar-scanner ready.
    [INFO] Running SonarQube analysis... (this may take a few minutes)
    
    Interface text:
    dryrun-1
    EXPLORER
    .claude
    .scannerwork
    .sonarlint
    .gitignore
    app.py
    apply-sonar.sh
    config.py
    database.py
    README.md
    sonar-project.proper...
    tasks.py
    ./apply-sonar.sh Untitled-1
    database.py > search_tasks
    PROBLEMS 1
    OUTPUT
    DEBUG CONSOLE
    TERMINAL
    PORTS
    SONARQUBE 1
    PIXEL AGENTS
    OUTLINE
    TIMELINE
    main
    SonarQube
    Killian Carlsen-Phelan (4 days ago)
    Ln 42, Col 19
    Spaces: 4
    UTF-8
    LF
    Python
    3.13.13
    Python 3.13.13

    17:43Demo milestone

  71. Search query construction

    search_tasks inserts a command-line query into an SQL f-string and executes it, creating the SQL injection vulnerability the speaker highlights while SonarQube analysis runs.

    Text in image
    database.py
    
    def add_task(title, priority=0):
        [lines 25–27 not visible]
        "INSERT INTO tasks (title, priority) VALUES (?, ?)", (title, priority)
        )
        conn.commit()
        conn.close()
    
    def search_tasks(query):
        """Search tasks by title."""
        conn = sqlite3.connect(DATABASE_PATH)
        cursor = conn.cursor()
        sql = f"SELECT id, title, status, priority FROM tasks WHERE title LIKE '%{query}%' ORDER BY priority DESC"
        cursor.execute(sql)
        results = cursor.fetchall()
        conn.close()
        return results
    
    def export_tasks(status_filter):
        """Export filtered tasks to a CSV file."""
        filename = [illegible]
    
    Terminal:
    > ./apply-sonar.sh
    [OK] Already authenticated with SonarQube Cloud.
    [INFO] Detected project configuration:
        Organization: kcarlsen-sonarsource
        Project key: kcarlsen-sonarsource_learn-codex-workshop
        Project name: learn-codex-workshop
    [OK] Project created: kcarlsen-sonarsource_learn-codex-workshop
    [OK] New code definition set to 'previous version'.
    [OK] sonar-project.properties Created.
    [OK] .sonarlint/connectedMode.json Created.
    [OK] sonar-scanner ready.
    [INFO] Running SonarQube analysis... (this may take a few minutes)
    
    Interface text:
    dryrun-1
    EXPLORER
    .claude
    .scannerwork
    .sonarlint
    .gitignore
    app.py
    apply-sonar.sh
    config.py
    database.py
    README.md
    sonar-project.proper...
    tasks.py
    ./apply-sonar.sh Untitled-1
    database.py > search_tasks
    PROBLEMS 1
    OUTPUT
    DEBUG CONSOLE
    TERMINAL
    PORTS
    SONARQUBE 1
    PIXEL AGENTS
    OUTLINE
    TIMELINE
    main
    SonarQube
    Killian Carlsen-Phelan (4 days ago)
    Ln 42, Col 19
    Spaces: 4
    UTF-8
    LF
    Python
    3.13.13
    Python 3.13.13

    17:51Demo milestone

  72. 17:55

    string. That is bad news bears, especially because this, um, function search task is being, uh, given an argument from sys.argv. That means that anybody who controls sys.argv gets to control your database, right? This is really bad. SonarQube is able to detect this and will let you know, "Hey, here is the data flow that we're detecting." It's using symbolic execution and taint

  73. SonarQube project setup and analysis

    The setup script creates the SonarQube project and starts analysis. While it runs, the demo shows a search command passing user input into an SQL f-string, which the speaker identifies as a SQL injection vulnerability.

    Text in image
    def main():
        [lines 30–44 not visible]
            title = sys.argv[2]
            priority = int(sys.argv[3]) if len(sys.argv) > 3 else 0
            add_task(title, priority)
            print(f"Task added: {title}")
    
        elif command == "search":
            if len(sys.argv) < 3:
                print("Usage: python app.py search <query>")
                sys.exit(1)
            results = search_tasks(sys.argv[2])
            print_tasks(results)
    
        elif command == "update":
            handle_update()
    
        elif command == "export":
            status = sys.argv[2] if len(sys.argv) > 2 else "open"
            path = export_tasks(status)
            print(f"Exported to {path}")
    
    Terminal:
    > ./apply-sonar.sh
    [OK] Already authenticated with SonarQube Cloud.
    [INFO] Detected project configuration:
        Organization: kcarlsen-sonarsource
        Project key: kcarlsen-sonarsource_learn-codex-workshop
        Project name: learn-codex-workshop
    [OK] Project created: kcarlsen-sonarsource_learn-codex-workshop
    [OK] New code definition set to 'previous version'.
    [OK] sonar-project.properties created.
    [OK] .sonarlint/connectedMode.json created.
    [OK] sonar-scanner ready.
    [INFO] Running SonarQube analysis... (this may take a few minutes)
    
    Interface text:
    EXPLORER
    DRYRUN-1
    .claude
    .scannerwork
    .sonarlint
    .gitignore
    app.py
    apply-sonar.sh
    config.py
    database.py
    README.md
    sonar-project.proper...
    tasks.py
    PROBLEMS 1
    OUTPUT
    DEBUG CONSOLE
    TERMINAL
    PORTS
    SONARQUBE 1
    PIXEL AGENTS

    18:02Demo milestone

  74. 18:25

    analysis to identify the data flow and, and trace it as it moves through your application.

  75. 18:33

    Um, there's gonna be a few things that we do as soon as this is set up. One of them is, um, in-installing the, the SonarQube Codex marketplace. Another one is wiring that to your project. And then another one is, um, making sure that everything is, is connected in the plugin. So this is almost done here. Apologize for that short wait, folks. Um, and if

  76. SonarQube project setup and analysis

    The setup script creates the SonarQube project and starts analysis. While it runs, the demo shows a search command passing user input into an SQL f-string, which the speaker identifies as a SQL injection vulnerability.

    Text in image
    def main():
        [lines 30–44 not visible]
            title = sys.argv[2]
            priority = int(sys.argv[3]) if len(sys.argv) > 3 else 0
            add_task(title, priority)
            print(f"Task added: {title}")
    
        elif command == "search":
            if len(sys.argv) < 3:
                print("Usage: python app.py search <query>")
                sys.exit(1)
            results = search_tasks(sys.argv[2])
            print_tasks(results)
    
        elif command == "update":
            handle_update()
    
        elif command == "export":
            status = sys.argv[2] if len(sys.argv) > 2 else "open"
            path = export_tasks(status)
            print(f"Exported to {path}")
    
    Terminal:
    > ./apply-sonar.sh
    [OK] Already authenticated with SonarQube Cloud.
    [INFO] Detected project configuration:
        Organization: kcarlsen-sonarsource
        Project key: kcarlsen-sonarsource_learn-codex-workshop
        Project name: learn-codex-workshop
    [OK] Project created: kcarlsen-sonarsource_learn-codex-workshop
    [OK] New code definition set to 'previous version'.
    [OK] sonar-project.properties created.
    [OK] .sonarlint/connectedMode.json created.
    [OK] sonar-scanner ready.
    [INFO] Running SonarQube analysis... (this may take a few minutes)
    
    Interface text:
    EXPLORER
    DRYRUN-1
    .claude
    .scannerwork
    .sonarlint
    .gitignore
    app.py
    apply-sonar.sh
    config.py
    database.py
    README.md
    sonar-project.proper...
    tasks.py
    PROBLEMS 1
    OUTPUT
    DEBUG CONSOLE
    TERMINAL
    PORTS
    SONARQUBE 1
    PIXEL AGENTS

    18:51Demo milestone

  77. 19:03

    you are running this yourself, hopefully it is, um, either finished so far or, or almost done. This will be done momentarily, but the three tools that I'm gonna focus on today are the, um, the secrets detection hook that we offer. We also have a, a list issues tool through Codex, and that allows you to see any of the issues from SonarQube within the terminal. And then the third one is being able to

  78. 19:33

    find and fix issues from those listed issues that we pull in, in, in the plugin itself.

  79. 19:42

    Any questions so far from anyone? If you have questions, by the way, if your setup's not working, we have our lovely team from Sonar over there. They're gonna wave hi real quick. Um, if you raise your hand and bump into anything, they are more than happy to come over and talk to you and, and help you through everything.

  80. SonarQube project setup and analysis

    The setup script creates the SonarQube project and starts analysis. While it runs, the demo shows a search command passing user input into an SQL f-string, which the speaker identifies as a SQL injection vulnerability.

    Text in image
    def main():
        [lines 30–44 not visible]
            title = sys.argv[2]
            priority = int(sys.argv[3]) if len(sys.argv) > 3 else 0
            add_task(title, priority)
            print(f"Task added: {title}")
    
        elif command == "search":
            if len(sys.argv) < 3:
                print("Usage: python app.py search <query>")
                sys.exit(1)
            results = search_tasks(sys.argv[2])
            print_tasks(results)
    
        elif command == "update":
            handle_update()
    
        elif command == "export":
            status = sys.argv[2] if len(sys.argv) > 2 else "open"
            path = export_tasks(status)
            print(f"Exported to {path}")
    
    Terminal:
    > ./apply-sonar.sh
    [OK] Already authenticated with SonarQube Cloud.
    [INFO] Detected project configuration:
        Organization: kcarlsen-sonarsource
        Project key: kcarlsen-sonarsource_learn-codex-workshop
        Project name: learn-codex-workshop
    [OK] Project created: kcarlsen-sonarsource_learn-codex-workshop
    [OK] New code definition set to 'previous version'.
    [OK] sonar-project.properties created.
    [OK] .sonarlint/connectedMode.json created.
    [OK] sonar-scanner ready.
    [INFO] Running SonarQube analysis... (this may take a few minutes)
    
    Interface text:
    EXPLORER
    DRYRUN-1
    .claude
    .scannerwork
    .sonarlint
    .gitignore
    app.py
    apply-sonar.sh
    config.py
    database.py
    README.md
    sonar-project.proper...
    tasks.py
    PROBLEMS 1
    OUTPUT
    DEBUG CONSOLE
    TERMINAL
    PORTS
    SONARQUBE 1
    PIXEL AGENTS

    19:51Demo milestone

  81. 20:04

    All right. Analysis complete, and I can go ahead and click into my dashboard.

  82. Analysis complete

    The completed scan provides a dashboard link. The terminal says the quality gate is not computed on the first scan and will evaluate on the next code change.

    Text in image
    def main():
    [lines 30–44 not visible]
            title = sys.argv[2]
            priority = int(sys.argv[3]) if len(sys.argv) > 3 else 0
            add_task(title, priority)
            print(f"Task added: {title}")
    
        elif command == "search":
            if len(sys.argv) < 3:
                print("Usage: python app.py search <query>")
                sys.exit(1)
            results = search_tasks(sys.argv[2])
            print_tasks(results)
    
        elif command == "update":
            handle_update()
    
        elif command == "export":
            status = sys.argv[2] if len(sys.argv) > 2 else "open"
            path = export_tasks(status)
            print(f"Exported to {path}")
    
    ./apply-sonar.sh
    Dashboard: https://sonarcloud.io/project/overview?id=kcarlsen-sonarsource_learn-codex-workshop
    Quality Gate: Not Computed — normal for a first scan. Push a change and scan again to see results.
    
    Config files:
      sonar-project.properties
      .sonarlint/connectedMode.json
    
    Next steps:
      • View your project: https://sonarcloud.io/project/overview?id=kcarlsen-sonarsource_learn-codex-workshop
      • The quality gate evaluates on your next code change
      • Add SONAR_TOKEN to your CI secrets for automated scanning
    
    Interface text:
    EXPLORER
    DRYRUN-1
    .claude
    .scannerwork
    .sonarlint
    .gitignore
    app.py
    apply-sonar.sh
    config.py
    database.py
    README.md
    sonar-project.proper...
    tasks.py
    app.py > main
    PROBLEMS 1
    OUTPUT
    DEBUG CONSOLE
    TERMINAL
    PORTS
    SONARQUBE 1
    PIXEL AGENTS
    OUTLINE
    TIMELINE
    dryrun-1 on main via v3.9.6 took 4m21s
    Ln 54, Col 30
    Spaces: 4
    UTF-8
    LF
    Python
    3.13.13

    20:06Demo milestone

  83. 20:17

    Open that up.

  84. 20:20

    Like I said, this is gonna be our SonarQube Cloud dashboard that shows you all of the issues that it's detected, um, within your project.

  85. 20:31

    And if you've had any issues with Wi-Fi or, or being able to install any of the prerequisites, um, again, no problem. This repo that you scanned, uh, the QR code for...

  86. 20:44

    Just reload that. That repo is going to be up for you.

  87. 21:00

    All right. So here's the dashboard. And I'm not gonna spend too much time here, um, but we can see here that the security rating is E. There are those three security issues. There are four total. And if I click on this, we can see here is that OpenAI API key that was able to detect, uh, that, that's here, um, just plain text in the source code. And if I go back, the other one I wanna focus on is this SQL

  88. Security dashboard

    The dashboard shows an E security rating and three security issues, split evenly across blocker, high, and medium severity. The presenter says there are four issues in total.

    Text in image
    Overview
    Private · No tags · 1.2k Lines of Code · Last analysis 3 minutes ago
    Downloadable reports
    Bind project
    
    Not computed
    Run analysis to generate status
    4
    No data available to display
    No data available to display
    
    Security snapshot
    
    Security Rating
    Overall code
    E
    
    Security Issues
    Overall code · Software quality: Secu...
    E
    3
    No change vs last 30 days
    
    Open Security Issues by Severity
    Overall code · Software quality: Security · Slice by: Severity
    Blocker 33%
    High 33%
    Medium 33%
    Legend: Blocker · High · Medium
    
    Security Hotspot snapshot
    Security Review Rating
    Overall code
    Security Hotspots
    Overall code
    A
    Security Hotspots by Review status
    Overall code · Slice by: Review status
    
    Interface text:
    SonarQube Cloud
    Favorite projects · Assigned issues · Portfolios · Explore
    To exit full screen, press and hold esc
    learn-codex-works... · Project
    Overview · Dashboards
    Analysis: Summary · Issues · Hunter Agent · Security h... Deprecated · Dependency risks
    Architecture: Current architecture · Intended architecture · Deviations
    Reporting: Security reports · Measures · Activity
    Policies: Quality profiles · Quality gate · License Profile
    Project: Pull Requests · Branches 1

    21:07Demo milestone

  89. 21:29

    injection vulnerability right here. This is the one I talked to, uh, y'all with the, the sys.argv issue, and this is taint analysis tracing the data flow from the source here all the way through different files and functions into the sink right here. Very, very helpful. All right. Popping back over to the terminal. Um, let me hop over to my handy dandy, uh, command clipboard that I

  90. Tracing the SQL injection source

    SonarQube traces potentially malicious input from sys.argv into search_tasks. The speaker follows its flow across files and functions to a SQL injection sink.

    Text in image
    Issues
    
    Make sure this OpenAI API key gets revoked, changed, and removed from the code.
    
    database.py
    LLMs running this code with faulty CLI arguments can cause SQL injections. Refactor this code to sanitize untrusted data before inserting them in queries.
    1 execution flow
    
    app.py
    1 SOURCE a user can craft an HTTP request with malicious content
    2 A malicious value was previously assigned to this data structure
    3 This instruction can propagate malicious content
    
    database.py
    4 This instruction can propagate malicious content
    5 This instruction can propagate malicious content
    6 The malicious content is concatenated into the string
    7 [illegible]
    
    Intentionality | Not complete
    
    LLMs running this code with faulty CLI arguments can cause SQL injections. Refactor this code to sanitize untrusted data before inserting them in queries.
    
    Agentic workflows should not be vulnerable to SQL injection attacks pythonsecurity:S8702 Beta
    Software qualities impacted: Security High
    Open in IDE
    Open · kcarlsen-sonarsource · Vulnerability · Major
    
    Tags
    CWE [illegible]
    Line affected
    L39
    Effort
    30 min
    Introduced
    3 days ago
    
    Where is the issue? | Why is this an issue? | How can I fix it? | Activity | More info
    
    /app.py
    See all issues in this file
    Show 48 lines
    
        elif command == "search":
            if len(sys.argv) < 3:
                print("Usage: python app.py search <query>")
                sys.exit(1)
            results = search_tasks(sys.argv[2])
            print_tasks(results)
    
        elif command == "update":
            handle_update()
    
    Show 13 lines
    Show all lines
    
    Interface text:
    SonarQube Cloud
    Favorite projects · Assigned issues · Portfolios · Explore
    learn-codex-works... · master
    Overview · Dashboards · Summary · Issues · Hunter Agent · Security h... Deprecated · Dependency risks · Current architecture · Intended architecture · Deviations · Security reports · Measures · Activity · Quality profiles · Quality gate · License Profile · Pull Requests · Branches
    Browser tabs: Killian AI WF deck - Google... · sonar-samples/learn-codex... · 404 Not found · Authorize SonarQube CLI? · Issues
    sonarcloud.io/project/issues?[illegible]

    21:35Demo milestone

  91. Tracing the SQL injection sink

    SonarQube traces untrusted CLI input through files and functions to the SQL execution sink, where the search query is assembled from that input.

    Text in image
    LLMs running this code with faulty CLI arguments can cause SQL injections. Refactor this code to sanitize untrusted data before inserting them in queries.
    
    Agentic workflows should not be vulnerable to SQL injection attacks pythonsecurity:S8702 Beta
    Software qualities impacted: Security, High
    
    Tags: CWE ...
    Line affected: L39
    Effort: 30 min
    Introduced: 3 days ago
    
    Execution flow:
    3 This instruction can propagate malicious content
    
    database.py
    4 This instruction can propagate malicious content
    5 This instruction can propagate malicious content
    6 The malicious content is concatenated into the string
    7 This concatenation can propagate malicious content to the newly created string
    8 A malicious value can be assigned to variable 'sql'
    9 SINK this invocation is not safe; a malicious value can be used as argument
    
    37 cursor = conn.cursor()
    38 sql = f"SELECT id, title, status, priority FROM tasks WHERE title LIKE '%{query}%' ORDER BY priority DESC"
    39 cursor.execute(sql)
    
    LLMs running this code with faulty CLI arguments can cause SQL injections. Refactor this code to sanitize untrusted data before inserting them in queries.
    
    40 results = cursor.fetchall()
    41 conn.close()
    42 return results
    
    45 def export_tasks(status_filter):
    46     """Export filtered tasks to a CSV file."""
    47     filename = tempfile.mktemp(suffix=".csv")
    
    ‘tempfile.mktemp’ is insecure. Use ‘tempfile.TemporaryFile’ instead.
    3 of 3 shown
    
    Interface text:
    SonarQube Cloud
    Favorite projects  Assigned issues  Portfolios  Explore
    Issues  master
    Overview  Dashboards
    Analysis: Summary  Issues  Hunter Agent  Security h... Deprecated  Dependency risks
    Architecture: Current architecture  Intended architecture  Deviations
    Reporting: Security reports  Measures  Activity
    Policies: Quality profiles  Quality gate  License Profile
    Project: Pull Requests  Branches
    Intentionality | Not complete
    Open in IDE
    Open  kcarlsen-sonarsource  Vulnerability  Major
    Where is the issue?  Why is this an issue?  How can I fix it?  Activity  More info
    Navigate locations
    Show 13 lines  Show all lines

    21:44Demo milestone

  92. Analysis complete

    The completed scan provides a dashboard link. The terminal says the quality gate is not computed on the first scan and will evaluate on the next code change.

    Text in image
    def main():
    [lines 30–44 not visible]
            title = sys.argv[2]
            priority = int(sys.argv[3]) if len(sys.argv) > 3 else 0
            add_task(title, priority)
            print(f"Task added: {title}")
    
        elif command == "search":
            if len(sys.argv) < 3:
                print("Usage: python app.py search <query>")
                sys.exit(1)
            results = search_tasks(sys.argv[2])
            print_tasks(results)
    
        elif command == "update":
            handle_update()
    
        elif command == "export":
            status = sys.argv[2] if len(sys.argv) > 2 else "open"
            path = export_tasks(status)
            print(f"Exported to {path}")
    
    ./apply-sonar.sh
    Dashboard: https://sonarcloud.io/project/overview?id=kcarlsen-sonarsource_learn-codex-workshop
    Quality Gate: Not Computed — normal for a first scan. Push a change and scan again to see results.
    
    Config files:
      sonar-project.properties
      .sonarlint/connectedMode.json
    
    Next steps:
      • View your project: https://sonarcloud.io/project/overview?id=kcarlsen-sonarsource_learn-codex-workshop
      • The quality gate evaluates on your next code change
      • Add SONAR_TOKEN to your CI secrets for automated scanning
    
    Interface text:
    EXPLORER
    DRYRUN-1
    .claude
    .scannerwork
    .sonarlint
    .gitignore
    app.py
    apply-sonar.sh
    config.py
    database.py
    README.md
    sonar-project.proper...
    tasks.py
    app.py > main
    PROBLEMS 1
    OUTPUT
    DEBUG CONSOLE
    TERMINAL
    PORTS
    SONARQUBE 1
    PIXEL AGENTS
    OUTLINE
    TIMELINE
    dryrun-1 on main via v3.9.6 took 4m21s
    Ln 54, Col 30
    Spaces: 4
    UTF-8
    LF
    Python
    3.13.13

    21:52Demo milestone

  93. 21:59

    have here. I'm going to do Codex, uh, plugin marketplace add, and what that's gonna do is that's just going to add the SonarQube marketplace here.

  94. Setting up the SonarQube plugin in Codex

    The presenter adds the SonarQube marketplace, then uses /plugins to find and install the plugin. Codex displays its available SonarQube skills.

    Text in image
    database.py
    
    def add_task(title, priority=0):
        [illegible]
            "INSERT INTO tasks (title, priority) VALUES (?, ?)", (title, priority)
        )
        conn.commit()
        conn.close()
    
    def search_tasks(query):
        """Search tasks by title."""
        conn = sqlite3.connect(DATABASE_PATH)
        cursor = conn.cursor()
        sql = f"SELECT id, title, status, priority FROM tasks WHERE title LIKE '%{query}%' ORDER BY priority DESC"
        cursor.execute(sql)
        results = cursor.fetchall()
        conn.close()
        return results
    
    def export_tasks(status_filter):
        """Export filtered tasks to a CSV file."""
        filename = tempfile.mktemp(suffix=".csv")
    
    Terminal:
    ./apply-sonar.sh
    
    Config files:
      sonar-project.properties
      .sonarlint/connectedMode.json
    
    Next steps:
      • View your project: https://sonarcloud.io/project/overview?id=kcarlsen-sonarsource_learn-codex-workshop
      • The quality gate evaluates on your next code change
      • Add SONAR_TOKEN to your CI secrets for automated scanning
    
    codex plugin marketplace add SonarSource/sonarqube-agent-plugins
    
    Interface text:
    EXPLORER
    DRYRUN-1
    .claude
    .scannerwork
    .sonarlint
    .gitignore
    app.py
    apply-sonar.sh
    config.py
    database.py
    README.md
    sonar-project.proper...
    tasks.py
    PROBLEMS 1  OUTPUT  DEBUG CONSOLE  TERMINAL  PORTS  SONARQUBE 1  PIXEL AGENTS

    22:11Demo milestone

  95. 22:13

    And, um, this, as soon as that's in, we're going to hop into, uh, Codex itself. We will see the SonarQube, uh, plugin available, and we'll be able to select that.

  96. 22:27

    So give that a few seconds. Uh, appreciate all of y'all folks being able to bear with me as I bump into just minor connectivity slowness. Again, in your normal agentic workflows, I'm sure things will be moving much faster for you.

  97. 22:45

    Perfect. I'm gonna pop open Codex. Sweet. And I'm going to do /plugins and then just search for SonarQube and install it. So that is get the marketplace, run it, /plugins, uh, invocation, and then type in SonarQube, and that is installed.

  98. Setting up the SonarQube plugin in Codex

    The presenter adds the SonarQube marketplace, then uses /plugins to find and install the plugin. Codex displays its available SonarQube skills.

    Text in image
    database.py
    
    def add_task(title, priority=0):
        [illegible]
            "INSERT INTO tasks (title, priority) VALUES (?, ?)", (title, priority)
        )
        conn.commit()
        conn.close()
    
    def search_tasks(query):
        """Search tasks by title."""
        conn = sqlite3.connect(DATABASE_PATH)
        cursor = conn.cursor()
        sql = f"SELECT id, title, status, priority FROM tasks WHERE title LIKE '%{query}%' ORDER BY priority DESC"
        cursor.execute(sql)
        results = cursor.fetchall()
        conn.close()
        return results
    
    def export_tasks(status_filter):
        """Export filtered tasks to a CSV file."""
        filename = tempfile.mktemp(suffix=".csv")
    
    Plugin details:
    1. Back to plugins  Return to the plugin list.
    2. Uninstall plugin  Remove this plugin now.
    Source  Local
    Auth  Auth on install
    Version  Local 1.1.[illegible]
    Skills  sonarqube:sonar-analyze, sonarqube:sonar-coverage, sonarqube:sonar-dependency-risks, sonarqube:sonar-duplication, sonarqube:sonar-fix-issue, sonarqube:sonar-integrate, sonarqube:sonar-list-issues, sonarqube:sonar-list-projects, sonarqube:sonar-quality-gate
    Hooks  No plugin hooks.
    Apps  No plugin apps.
    Press esc to close.
    
    Interface text:
    EXPLORER
    DRYRUN-1
    .claude
    .scannerwork
    .sonarlint
    .gitignore
    app.py
    apply-sonar.sh
    config.py
    database.py
    README.md
    sonar-project.proper...
    tasks.py
    PROBLEMS 1  OUTPUT  DEBUG CONSOLE  TERMINAL  PORTS  SONARQUBE 1  PIXEL AGENTS

    22:53Demo milestone

  99. CLI authentication prompt

    Carlsen-Phelan runs sonar auth login. The CLI finds the configured SonarCloud server and prompts him to open a browser to obtain an access token.

    Text in image
    sonar auth login
    Found server in .sonarlint config: https://sonarcloud.io
    
    Authenticating with: https://sonarcloud.io
    Obtaining access token from SonarQube...
    URL: https://sonarcloud.io/auth?product=cli&port=64124
    Press Enter to open the browser
    
    Visible code:
    def add_task(title, priority=0):
        [illegible]
            "INSERT INTO tasks (title, priority) VALUES (?, ?)", (title, priority)
        )
        conn.commit()
        conn.close()
    
    def search_tasks(query):
        """Search tasks by title."""
        conn = sqlite3.connect(DATABASE_PATH)
        cursor = conn.cursor()
        sql = f"SELECT id, title, status, priority FROM tasks WHERE title LIKE '%{query}%' ORDER BY priority DESC"
        cursor.execute(sql)
        results = cursor.fetchall()
        conn.close()
        return results
    
    def export_tasks(status_filter):
        """Export filtered tasks to a CSV file."""
        filename = [illegible]
    
    Interface text:
    EXPLORER
    DRYRUN-1
    .claude
    .scannerwork
    .sonarlint
    .gitignore
    app.py
    apply-sonar.sh
    config.py
    database.py
    README.md
    sonar-project.proper...
    tasks.py
    PROBLEMS 1
    OUTPUT
    DEBUG CONSOLE
    TERMINAL
    PORTS
    SONARQUBE 1
    PIXEL AGENTS
    OUTLINE
    TIMELINE

    23:10Demo milestone

  100. 23:12

    All right, I'm gonna exit out of this so that it can reload and so I can just run a couple more commands. Um, I'm going to, uh, say sonar

  101. 23:24

    auth login.

  102. 23:27

    That's just gonna authenticate the CLI, um, which, uh, will allow us to use a lot of the capabilities that the plugin is built off of.

  103. 23:41

    After that, uh, we're gonna get to finally the, the final wiring step, which is just Sonar integrate Codex as soon as this gets off for us. Yep. Allow that. Perfect.

  104. SonarQube Cloud setup

    Carlsen-Phelan runs his personal Apply Sonar script, then authorizes the connection in a browser. The success page says the token was sent to the terminal to finish setup.

    Text in image
    Connection successful!
    
    Your user token has now been generated & sent to your terminal.
    
    Return to your terminal to complete the setup.
    
    Interface text:
    SonarQube Cloud
    Authorize SonarQube CLI?
    sonarcloud.io/auth?product=cli&port=64124

    23:51Demo milestone

  105. Authentication succeeds

    SonarQube authentication succeeds for the configured organization. The presenter says the next step is to run the Codex integration command.

    Text in image
    def add_task(title, priority=0):
        [illegible]
            "INSERT INTO tasks (title, priority) VALUES (?, ?)", (title, priority)
        )
        conn.commit()
        conn.close()
    
    def search_tasks(query):
        """Search tasks by title."""
        conn = sqlite3.connect(DATABASE_PATH)
        cursor = conn.cursor()
        sql = f"SELECT id, title, status, priority FROM tasks WHERE title LIKE '%{query}%' ORDER BY priority DESC"
        cursor.execute(sql)
        results = cursor.fetchall()
        conn.close()
        return results
    
    def export_tasks(status_filter):
        """Export filtered tasks to a CSV file."""
        filename = tempfile.mktemp(suffix=".csv")
    
    Terminal:
    sonar auth login
    Found server in .sonarlint config: https://sonarcloud.io
    
    Authenticating with: https://sonarcloud.io
    Obtaining access token from SonarQube...
    URL: https://sonarcloud.io/auth?product=cli&port=64124
    Press Enter to open the browser
    Waiting for authorization... or paste token and press Enter:
    Token received
    Using organization from config: kcarlsen-sonarsource
    Authentication successful for: https://sonarcloud.io (kcarlsen-sonarsource)
    
    Interface text:
    EXPLORER
    DRYRUN-1
    .claude
    .scannerwork
    .sonarlint
    .gitignore
    app.py
    apply-sonar.sh
    config.py
    database.py
    README.md
    sonar-project.proper...
    tasks.py
    OUTLINE
    TIMELINE
    PROBLEMS 1
    OUTPUT
    DEBUG CONSOLE
    TERMINAL
    PORTS
    SONARQUBE 1
    PIXEL AGENTS
    main
    SonarQube
    Killian Carlsen-Phelan (4 days ago)
    Ln 42, Col 19
    Spaces: 4
    UTF-8
    LF
    Python
    3.13.13
    Python 3.13.13

    23:55Demo milestone

  106. 24:01

    So that will take hopefully not too, too much longer, a couple seconds, get that updated, and then we'll write, um, do this integrate Codex command here.

  107. CLI authentication prompt

    Carlsen-Phelan runs sonar auth login. The CLI finds the configured SonarCloud server and prompts him to open a browser to obtain an access token.

    Text in image
    sonar auth login
    Found server in .sonarlint config: https://sonarcloud.io
    
    Authenticating with: https://sonarcloud.io
    Obtaining access token from SonarQube...
    URL: https://sonarcloud.io/auth?product=cli&port=64124
    Press Enter to open the browser
    
    Visible code:
    def add_task(title, priority=0):
        [illegible]
            "INSERT INTO tasks (title, priority) VALUES (?, ?)", (title, priority)
        )
        conn.commit()
        conn.close()
    
    def search_tasks(query):
        """Search tasks by title."""
        conn = sqlite3.connect(DATABASE_PATH)
        cursor = conn.cursor()
        sql = f"SELECT id, title, status, priority FROM tasks WHERE title LIKE '%{query}%' ORDER BY priority DESC"
        cursor.execute(sql)
        results = cursor.fetchall()
        conn.close()
        return results
    
    def export_tasks(status_filter):
        """Export filtered tasks to a CSV file."""
        filename = [illegible]
    
    Interface text:
    EXPLORER
    DRYRUN-1
    .claude
    .scannerwork
    .sonarlint
    .gitignore
    app.py
    apply-sonar.sh
    config.py
    database.py
    README.md
    sonar-project.proper...
    tasks.py
    PROBLEMS 1
    OUTPUT
    DEBUG CONSOLE
    TERMINAL
    PORTS
    SONARQUBE 1
    PIXEL AGENTS
    OUTLINE
    TIMELINE

    24:15Demo milestone

  108. 24:26

    Oh, looks like it's running into some more, um...

  109. 24:32

    Try that. Looks like for some reason the, the Sonar token which is exported is getting lost.

  110. 24:43

    Okay.

  111. 24:45

    Sonar.

  112. 24:50

    Pop back in for y'all real quick.

  113. 25:01

    See if you can't see my screen again.

  114. Task database initialization

    The task manager initializes a SQLite table with required titles, an open status, a default priority of 0, and creation timestamps.

    Text in image
    """Database operations for the task manager."""
    
    import sqlite3
    import tempfile
    from config import DATABASE_PATH
    
    
    def init_db():
        conn = sqlite3.connect(DATABASE_PATH)
        cursor = conn.cursor()
        cursor.execute("""
            CREATE TABLE IF NOT EXISTS tasks (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                title TEXT NOT NULL,
                status TEXT DEFAULT 'open',
                priority INTEGER DEFAULT 0,
                created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
            )
        """)
        conn.commit()
        conn.close()
    
    Interface text:
    EXPLORER
    DRYRUN-1
    .claude
    .scannerwork
    .sonarlint
    .gitignore
    app.py
    apply-sonar.sh
    config.py
    database.py
    README.md
    sonar-project.proper...
    tasks.py
    app.py | database.py | ./apply-sonar.sh Untitled-1
    database.py > search_tasks
    PROBLEMS 1 | OUTPUT | DEBUG CONSOLE | TERMINAL | PORTS | SONARQUBE 1 | PIXEL AGENTS
    dryrun-1 on main via v3.9.6
    OUTLINE | TIMELINE
    main | SonarQube | Killian Carlsen-Phelan (4 days ago) | Ln 42, Col 19 | Spaces: 4 | UTF-8 | LF | Python | 3.13.13 | Python 3.13.13

    25:06Demo milestone

  115. 25:07

    Perfect.

  116. 25:11

    I'm gonna go to the clipboard and pull this back over.

  117. 25:21

    All right. So, uh, what this is gonna do is a few different things. This is going to get you your secrets detection hook. This is going to get you your agent's, uh, MD directive to use all the SonarQube skills, and this is going to give you, um, other skills and, uh, the MCP config as well.

  118. 25:45

    It's perfect. This is just gonna go on a little bit longer, and then everything will be fully wired up to use the SonarQube Codex plugin.

  119. 25:56

    Quick time check. Okay, we should be good.

  120. 26:02

    So for me, this is going to install, uh, two extra things that some of you who are using the free account may not see. That is context augmentation, and that is agentic analysis. Uh, agentic analysis is a hook that fires instantly after any edit that the agent does. So if you tell it to write a file or modify any file, it will automatically execute, and that runs server-side analysis on the code that was just

  121. 26:32

    written. What context augmentation does is it detects, hey, when it's about to do something, when Codex is about to perform a task, then it will feed it with the, the guidelines and, uh, relevant architecture and other information like that. Okay. We are, we are finally rocking and rolling here, folks. We have a few things that were added, um, specifically some hooks in here. There are some skills under the hood as well, and I'm going to copy this real quick.

  122. 27:03

    So I'm gonna pop open Codex, trust all of these hooks. Thank you, Sandbox. And the s-- uh, the MCP server is getting booted up with SonarQube. What I'm going to do is I'm going to say, "Hey, can you push a commit using my token?" This is a, a fake secret that, um, the, the plugin suggests that you try with immediately. Say sure.

  123. 27:32

    So you can see instantly this was blocked. No secrets were leaked into the L1 context. Nothing is being stored in any logs or anything like that. As well, if you ask it to read a file with a secret in it, it will not do it. It will be blocked. Codex never gets to look at any of your, uh, secrets or anything like that, that are, that are being leaked into your context. This is super important. People do it all the time. We all know what to do.

  124. 28:01

    Yes.

  125. 28:02

    I have one question.

  126. 28:03

    Mm-hmm.

  127. 28:03

    Is there a chance that the Codex will write a script to read the file?

  128. 28:08

    Write a script to read the file?

  129. 28:09

    Yeah.

  130. 28:11

    So-

  131. 28:12

    I've seen such scenario.

  132. 28:13

    That's possible. Um, this mainly works on the tool use, right? It's, it's a hook that's invoked on, on the, the user prompt submit tool. So if that is bypassed, then it is possible that that hook may not be invoked. But for basic usage of, um, Codex and its tools and, and, and prompting it and things like that, if you leak any, um, secrets into the prompt or if there's anything, it will detect that. Uh, looks like we're having a little

  133. 28:43

    bit of internet connectivity right here. Uh, I'm gonna relaunch up that MCP server real quick.

  134. SonarQube MCP startup failure

    Codex reports a SonarQube MCP startup failure while loading its inventory. The presenter cites connectivity trouble and plans to relaunch the server.

    Text in image
    def main():
        [lines 30–44 not visible]
            title = sys.argv[2]
            priority = int(sys.argv[3]) if len(sys.argv) > 3 else 0
            add_task(title, priority)
            print(f"Task added: {title}")
    
        elif command == "search":
            if len(sys.argv) < 3:
                print("Usage: python app.py search <query>")
                sys.exit(1)
            results = search_tasks(sys.argv[2])
            print_tasks(results)
    
        elif command == "update":
            handle_update()
    
        elif command == "export":
            status = sys.argv[2] if len(sys.argv) > 2 else "open"
            path = export_tasks(status)
            print(f"Exported to {path}")
    
    startup_timeout_sec = XX
    MCP startup incomplete (failed: sonarqube)
    Loading MCP inventory.
    
    Interface text:
    dryrun-1
    EXPLORER
    DRYRUN-1
    .agents
    .claude
    .codex
    hooks
    sonar-secrets
    sonar-sqaa
    config.toml
    hooks.json
    .scannerwork
    .sonarlint
    .gitignore
    AGENTS.md
    app.py
    apply-sonar.sh
    config.py
    database.py
    README.md
    sonar-project.proper...
    tasks.py
    app.py > main
    PROBLEMS 1
    OUTPUT
    DEBUG CONSOLE
    TERMINAL
    PORTS
    SONARQUBE 1
    PIXEL AGENTS
    Run /review on my current changes
    gpt-5.5 medium · ~/dev/dryrun-1
    OUTLINE
    TIMELINE
    main
    SonarQube
    Killian Carlsen-Phelan (4 days ago)
    Ln 54, Col 30
    Spaces: 4
    UTF-8
    LF
    Python
    3.13.13
    Python 3.13.13

    28:54Demo milestone

  135. MCP inventory reports no tools

    Codex reports that SonarQube MCP startup failed and lists no available tools. The presenter plans to restart the server, which he says connects Codex with the SonarQube Cloud dashboard.

    Text in image
    def main():
        [lines 30–44 not shown]
            title = sys.argv[2]
            priority = int(sys.argv[3]) if len(sys.argv) > 3 else 0
            add_task(title, priority)
            print(f"Task added: {title}")
    
        elif command == "search":
            if len(sys.argv) < 3:
                print("Usage: python app.py search <query>")
                sys.exit(1)
            results = search_tasks(sys.argv[2])
            print_tasks(results)
    
        elif command == "update":
            handle_update()
    
        elif command == "export":
            status = sys.argv[2] if len(sys.argv) > 2 else "open"
            path = export_tasks(status)
    
    MCP startup incomplete (failed: sonarqube)
    
    /mcp
    
    MCP Tools
    - No MCP tools available.
    - sonarqube
      - Auth: Unsupported
      - Tools: (none)
    
    Run /review on my current changes
    
    Interface text:
    dryrun-1
    EXPLORER
    DRYRUN-1
    .agents
    .claude
    .codex
    hooks
    sonar-secrets
    sonar-sqaa
    config.toml
    hooks.json
    .scannerwork
    .sonarlint
    .gitignore
    AGENTS.md
    app.py
    apply-sonar.sh
    config.py
    database.py
    README.md
    sonar-project.proper...
    tasks.py
    OUTLINE
    TIMELINE
    app.py > main
    PROBLEMS 1
    OUTPUT
    DEBUG CONSOLE
    TERMINAL
    PORTS
    SONARQUBE 1
    PIXEL AGENTS
    gpt-5.5 medium · ~/dev/dryrun-1
    main
    SonarQube
    Killian Carlsen-Phelan (4 days ago)
    Ln 54, Col 30
    Spaces: 4
    UTF-8
    LF
    Python
    3.13.13
    Python 3.13.13

    28:58Demo milestone

  136. 29:00

    And so what the MCP server is going to allow us to do is to use the skills that allow us to interact, uh, w-- between Codex and, and the SonarQube Cloud, uh, dashboard that we saw earlier. For instance, if we were to say, "Hey, list all of the issues in my project," it's able to fetch that and, uh, and return information to us. I'm just gonna go ahead and exit out of this real quick and open it back up.

  137. Requesting SonarQube project issues in Codex

    After relaunching Codex, the presenter asks it to list project issues. The terminal reports no MCP tools available and shows Codex still working; no issue list is visible yet.

    Text in image
    def main():
        [lines 30–44 not visible]
            title = sys.argv[2]
            priority = int(sys.argv[3]) if len(sys.argv) > 3 else 0
            add_task(title, priority)
            print(f"Task added: {title}")
    
        elif command == "search":
            if len(sys.argv) < 3:
                print("Usage: python app.py search <query>")
                sys.exit(1)
            results = search_tasks(sys.argv[2])
            print_tasks(results)
    
        elif command == "update":
            handle_update()
    
    Terminal:
    dryrun-1 on main via v3.9.6 took 2m25s
    > codex
    See https://github.com/openai/codex for installation options.
    See full release notes:
    
    OpenAI Codex (v0.142.0)
    model: gpt-5.5 medium /model to change
    directory: ~/dev/dryrun-1
    
    Tip: Run codex app to open Codex Desktop (it installs on macOS if needed).
    > Summarize recent commits
    gpt-5.5 medium · ~/dev/dryrun-1
    
    Interface text:
    EXPLORER
    DRYRUN-1
    .agents
    .claude
    .codex
    hooks
    sonar-secrets
    sonar-sqaa
    config.toml
    hooks.json
    .scannerwork
    .sonarlint
    .gitignore
    AGENTS.md
    app.py
    apply-sonar.sh
    config.py
    database.py
    README.md
    sonar-project.proper...
    tasks.py
    OUTLINE
    TIMELINE
    app.py
    database.py 1
    ./apply-sonar.sh Untitled-1
    PROBLEMS 1
    OUTPUT
    DEBUG CONSOLE
    TERMINAL
    PORTS
    SONARQUBE 1
    PIXEL AGENTS
    main
    SonarQube
    Killian Carlsen-Phelan (4 days ago)
    Ln 54, Col 30
    Spaces: 4
    UTF-8
    LF
    Python
    3.13.13
    Python 3.13.13

    29:32Demo milestone

  138. 29:35

    And get that SonarQube MCP server booted right back up.

  139. 29:45

    Yes.

  140. 29:46

    Just playing around with Sonar as well. Um, so I actually am a L1 engineer, so the full setup process there is kind of a long wait process. How much do you think that actually just kind of terms of work period versus, versus the items that you put together expected?

  141. 30:02

    I am very sorry. It's hard for me to hear. Would you mind walking up or speaking a little loud-- louder?

  142. 30:08

    Okay. Uh, um, so the question is, in this whole setup process-

  143. 30:13

    Mm-hmm.

  144. 30:13

    You know, we have a network.

  145. 30:15

    Yes.

  146. 30:15

    So there's plenty of time where you see it's actually budgeting for the placement like ten millisecond-

  147. 30:21

    Mm-hmm

  148. 30:30

    Running this on my own, the Apply Sonar script that get, uh, gets us all provisioned, for me, never takes longer than a minute if I'm running it on my own. Um, everything else, the MCP, it's, is about as long as any other MCP that it takes, assuming normal connectivity. Um, I'm doing my best to work with the connectivity here, but, um, outside of that, I would say there's no extra, uh, overhead that any of these really apply for or, or any of these add to a normal, um, developer

  149. 31:00

    workflow.

  150. SonarQube MCP startup failure

    Codex reports a SonarQube MCP startup failure while loading its inventory. The presenter cites connectivity trouble and plans to relaunch the server.

    Text in image
    def main():
        [lines 30–44 not visible]
            title = sys.argv[2]
            priority = int(sys.argv[3]) if len(sys.argv) > 3 else 0
            add_task(title, priority)
            print(f"Task added: {title}")
    
        elif command == "search":
            if len(sys.argv) < 3:
                print("Usage: python app.py search <query>")
                sys.exit(1)
            results = search_tasks(sys.argv[2])
            print_tasks(results)
    
        elif command == "update":
            handle_update()
    
        elif command == "export":
            status = sys.argv[2] if len(sys.argv) > 2 else "open"
            path = export_tasks(status)
            print(f"Exported to {path}")
    
    startup_timeout_sec = XX
    MCP startup incomplete (failed: sonarqube)
    Loading MCP inventory.
    
    Interface text:
    dryrun-1
    EXPLORER
    DRYRUN-1
    .agents
    .claude
    .codex
    hooks
    sonar-secrets
    sonar-sqaa
    config.toml
    hooks.json
    .scannerwork
    .sonarlint
    .gitignore
    AGENTS.md
    app.py
    apply-sonar.sh
    config.py
    database.py
    README.md
    sonar-project.proper...
    tasks.py
    app.py > main
    PROBLEMS 1
    OUTPUT
    DEBUG CONSOLE
    TERMINAL
    PORTS
    SONARQUBE 1
    PIXEL AGENTS
    Run /review on my current changes
    gpt-5.5 medium · ~/dev/dryrun-1
    OUTLINE
    TIMELINE
    main
    SonarQube
    Killian Carlsen-Phelan (4 days ago)
    Ln 54, Col 30
    Spaces: 4
    UTF-8
    LF
    Python
    3.13.13
    Python 3.13.13

    31:03Demo milestone

  151. 31:04

    So I'm gonna double-check that the MCP is, uh, up and running real quick.

  152. 31:14

    And, um, like I said, what, what the MCP does is allows you to have access to all of the tools to where any time you ask it to do something related to, uh, Sonar, like the issues in your project, it automatically detects what's going on, um, and, and will invoke any of those relevant skills. One of those skills is context augmentation, which is knowing that, okay, we have the SonarQube tools, but our network does not seem to be populating, uh,

  153. Requesting SonarQube project issues in Codex

    After relaunching Codex, the presenter asks it to list project issues. The terminal reports no MCP tools available and shows Codex still working; no issue list is visible yet.

    Text in image
    def main():
        [lines 30–44 not visible]
            title = sys.argv[2]
            priority = int(sys.argv[3]) if len(sys.argv) > 3 else 0
            add_task(title, priority)
            print(f"Task added: {title}")
    
        elif command == "search":
            if len(sys.argv) < 3:
                print("Usage: python app.py search <query>")
                sys.exit(1)
            results = search_tasks(sys.argv[2])
            print_tasks(results)
    
        elif command == "update":
            handle_update()
    
    Terminal:
    dryrun-1 on main via v3.9.6 took 2m25s
    > codex
    See https://github.com/openai/codex for installation options.
    See full release notes:
    
    OpenAI Codex (v0.142.0)
    model: gpt-5.5 medium /model to change
    directory: ~/dev/dryrun-1
    
    Tip: Run codex app to open Codex Desktop (it installs on macOS if needed).
    > Summarize recent commits
    gpt-5.5 medium · ~/dev/dryrun-1
    
    Interface text:
    EXPLORER
    DRYRUN-1
    .agents
    .claude
    .codex
    hooks
    sonar-secrets
    sonar-sqaa
    config.toml
    hooks.json
    .scannerwork
    .sonarlint
    .gitignore
    AGENTS.md
    app.py
    apply-sonar.sh
    config.py
    database.py
    README.md
    sonar-project.proper...
    tasks.py
    OUTLINE
    TIMELINE
    app.py
    database.py 1
    ./apply-sonar.sh Untitled-1
    PROBLEMS 1
    OUTPUT
    DEBUG CONSOLE
    TERMINAL
    PORTS
    SONARQUBE 1
    PIXEL AGENTS
    main
    SonarQube
    Killian Carlsen-Phelan (4 days ago)
    Ln 54, Col 30
    Spaces: 4
    UTF-8
    LF
    Python
    3.13.13
    Python 3.13.13

    31:34Demo milestone

  154. 31:43

    the MCP with any of that.

  155. 31:48

    Let me see, let me see if it'll work with us regardless. Let me say, "List the issues in my project."

  156. Requesting SonarQube project issues in Codex

    After relaunching Codex, the presenter asks it to list project issues. The terminal reports no MCP tools available and shows Codex still working; no issue list is visible yet.

    Text in image
    def main():
        [lines 30–44 not visible]
            title = sys.argv[2]
            priority = int(sys.argv[3]) if len(sys.argv) > 3 else 0
            add_task(title, priority)
            print(f"Task added: {title}")
    
        elif command == "search":
            if len(sys.argv) < 3:
                print("Usage: python app.py search <query>")
                sys.exit(1)
            results = search_tasks(sys.argv[2])
            print_tasks(results)
    
        elif command == "update":
            handle_update()
    
    Terminal:
    dryrun-1 on main via v3.9.6 took 2m25s
    > codex
    See https://github.com/openai/codex for installation options.
    See full release notes:
    
    OpenAI Codex (v0.142.0)
    model: gpt-5.5 medium /model to change
    directory: ~/dev/dryrun-1
    
    Tip: Run codex app to open Codex Desktop (it installs on macOS if needed).
    > Summarize recent commits
    gpt-5.5 medium · ~/dev/dryrun-1
    
    Interface text:
    EXPLORER
    DRYRUN-1
    .agents
    .claude
    .codex
    hooks
    sonar-secrets
    sonar-sqaa
    config.toml
    hooks.json
    .scannerwork
    .sonarlint
    .gitignore
    AGENTS.md
    app.py
    apply-sonar.sh
    config.py
    database.py
    README.md
    sonar-project.proper...
    tasks.py
    OUTLINE
    TIMELINE
    app.py
    database.py 1
    ./apply-sonar.sh Untitled-1
    PROBLEMS 1
    OUTPUT
    DEBUG CONSOLE
    TERMINAL
    PORTS
    SONARQUBE 1
    PIXEL AGENTS
    main
    SonarQube
    Killian Carlsen-Phelan (4 days ago)
    Ln 54, Col 30
    Spaces: 4
    UTF-8
    LF
    Python
    3.13.13
    Python 3.13.13

    31:52Demo milestone

    Show 2 builds
    1. 29:32

      The relaunched Codex interface appears in the editor terminal.

      Text in image
      def main():
          [lines 30–44 not visible]
              title = sys.argv[2]
              priority = int(sys.argv[3]) if len(sys.argv) > 3 else 0
              add_task(title, priority)
              print(f"Task added: {title}")
      
          elif command == "search":
              if len(sys.argv) < 3:
                  print("Usage: python app.py search <query>")
                  sys.exit(1)
              results = search_tasks(sys.argv[2])
              print_tasks(results)
      
          elif command == "update":
              handle_update()
      
      Terminal:
      dryrun-1 on main via v3.9.6 took 2m25s
      > codex
      See https://github.com/openai/codex for installation options.
      See full release notes:
      
      OpenAI Codex (v0.142.0)
      model: gpt-5.5 medium /model to change
      directory: ~/dev/dryrun-1
      
      Tip: Run codex app to open Codex Desktop (it installs on macOS if needed).
      > Summarize recent commits
      gpt-5.5 medium · ~/dev/dryrun-1
      
      Interface text:
      EXPLORER
      DRYRUN-1
      .agents
      .claude
      .codex
      hooks
      sonar-secrets
      sonar-sqaa
      config.toml
      hooks.json
      .scannerwork
      .sonarlint
      .gitignore
      AGENTS.md
      app.py
      apply-sonar.sh
      config.py
      database.py
      README.md
      sonar-project.proper...
      tasks.py
      OUTLINE
      TIMELINE
      app.py
      database.py 1
      ./apply-sonar.sh Untitled-1
      PROBLEMS 1
      OUTPUT
      DEBUG CONSOLE
      TERMINAL
      PORTS
      SONARQUBE 1
      PIXEL AGENTS
      main
      SonarQube
      Killian Carlsen-Phelan (4 days ago)
      Ln 54, Col 30
      Spaces: 4
      UTF-8
      LF
      Python
      3.13.13
      Python 3.13.13
    2. 31:56

      Codex receives a request to list project issues; the terminal reports no MCP tools available.

      Text in image
      def main():
          [lines 30–44 not visible]
              title = sys.argv[2]
              priority = int(sys.argv[3]) if len(sys.argv) > 3 else 0
              add_task(title, priority)
              print(f"Task added: {title}")
      
          elif command == "search":
              if len(sys.argv) < 3:
                  print("Usage: python app.py search <query>")
                  sys.exit(1)
              results = search_tasks(sys.argv[2])
              print_tasks(results)
      
          elif command == "update":
              handle_update()
      
      Terminal:
      dryrun-1 on main via v3.9.6 took 2m25s
      > codex
      • No MCP tools available.
      • sonarqube
        • Auth: Unsupported
        • Tools: (none)
      
      > list the issues in my project
      • Working (15s • esc to interrupt)
      > Summarize recent commits
      gpt-5.5 medium · ~/dev/dryrun-1
      
      Interface text:
      EXPLORER
      DRYRUN-1
      .agents
      .claude
      .codex
      hooks
      sonar-secrets
      sonar-sqaa
      config.toml
      hooks.json
      .scannerwork
      .sonarlint
      .gitignore
      AGENTS.md
      app.py
      apply-sonar.sh
      config.py
      database.py
      README.md
      sonar-project.proper...
      tasks.py
      OUTLINE
      TIMELINE
      app.py
      database.py 1
      ./apply-sonar.sh Untitled-1
      PROBLEMS 1
      OUTPUT
      DEBUG CONSOLE
      TERMINAL
      PORTS
      SONARQUBE 1
      PIXEL AGENTS
      main
      SonarQube
      Killian Carlsen-Phelan (4 days ago)
      Ln 54, Col 30
      Spaces: 4
      UTF-8
      LF
      Python
      3.13.13
      Python 3.13.13
  157. 32:00

    Um, any other questions so far? Figure I might as well take a few while we're waiting. Yes.

  158. 32:06

    Can you explain how the MCP interacts with the Sonar CLI? What's the relationship?

  159. 32:10

    Yeah. So the, the, the CLI, um, actually only sets up the configuration. The MCP runs within Docker. So it will sometimes go through the MCP if it's using any of the skills, um, that it has there. But for the most part, this plugin and everything just sets up the configuration and then invokes, um, skills through there.

  160. 32:34

    It utilizes local commands to set up?

  161. 32:37

    The, the, the CLI helps you provision and set up the MCP and everything like that, and then there are commands that you're able to, to invoke through the MCP with the CLI. And I wanna clarify the difference. There's a CLI that this plugin lives on top of. So there are certain things where you could say, "Hey, execute, um, you know, this, this task for me," and it may route through, route it through an MCP skill or through a CLI command.

  162. 33:06

    Okay. So looks like we have the MCP. It's just running very slow because of network, because it was able to detect that for us. Sonar list issues skill, as well as this context augmentation skill.

  163. 33:20

    We can also see that, hey, even when it's looking at its skills, we are running the secret scan and making sure that there are no, uh, API keys, nothing like that, uh, leaked in, uh, when it, when it takes a look at, at any of its files, including its own skill files.

  164. Scanning and reading skills

    Codex scans the Sonar context and issue-listing skill files for secrets before reading them. Both scans complete successfully.

    Text in image
    I’ll use the Sonar context skill first as required, then the Sonar issue-listing workflow. I’m going to scan each instruction file before reading it, per this workspace’s protocol.
    
    Ran sonar analyze secrets .agents/skills/sonar-context-augmentation/SKILL.md
      Secrets scan completed successfully
    
    Ran sonar analyze secrets /Users/killian.carlsenphelan/.codex/plugins/cache/sonar/sonarqube/1.1.0/skills/sonar-list-issues/SKILL.md
      Secrets scan completed successfully
    
    Explored
      Read SKILL.md (sonarqube:sonar-list-issues skill), SKILL.md (sonar-context-augmentation skill)
    
    Interface text:
    EXPLORER
    DRYRUN-1
    .agents
    .claude
    .codex
      hooks
        sonar-secrets
        sonar-sqaa
      config.toml
      hooks.json
    .scannerwork
    .sonarlint
    .gitignore
    AGENTS.md
    app.py
    apply-sonar.sh
    config.py
    database.py
    README.md
    sonar-project.proper...
    tasks.py
    
    app.py > main
    def main():
    [lines 30–44 not shown]
            title = sys.argv[2]
            priority = int(sys.argv[3]) if len(sys.argv) > 3 else 0
            add_task(title, priority)
            print(f"Task added: {title}")
    
        elif command == "search":
            if len(sys.argv) < 3:
                print("Usage: python app.py search <query>")
                sys.exit(1)
            results = search_tasks(sys.argv[2])
            print_tasks(results)
    
        elif command == "update":
            handle_update()
    
    PROBLEMS 1  OUTPUT  DEBUG CONSOLE  TERMINAL  PORTS  SONARQUBE 1  PIXEL AGENTS
    dryrun-1 on main via v3.9.6 took 2m25s
    > codex
    OUTLINE
    TIMELINE
    main  SonarQube  Killian Carlsen-Phelan (4 days ago)  Ln 54, Col 30  Spaces: 4  UTF-8  LF  Python  3.13.13  Python 3.13.13

    33:21Demo milestone

  165. Requesting SonarQube project issues in Codex

    After relaunching Codex, the presenter asks it to list project issues. The terminal reports no MCP tools available and shows Codex still working; no issue list is visible yet.

    Text in image
    def main():
        [lines 30–44 not visible]
            title = sys.argv[2]
            priority = int(sys.argv[3]) if len(sys.argv) > 3 else 0
            add_task(title, priority)
            print(f"Task added: {title}")
    
        elif command == "search":
            if len(sys.argv) < 3:
                print("Usage: python app.py search <query>")
                sys.exit(1)
            results = search_tasks(sys.argv[2])
            print_tasks(results)
    
        elif command == "update":
            handle_update()
    
    Terminal:
    dryrun-1 on main via v3.9.6 took 2m25s
    > codex
    See https://github.com/openai/codex for installation options.
    See full release notes:
    
    OpenAI Codex (v0.142.0)
    model: gpt-5.5 medium /model to change
    directory: ~/dev/dryrun-1
    
    Tip: Run codex app to open Codex Desktop (it installs on macOS if needed).
    > Summarize recent commits
    gpt-5.5 medium · ~/dev/dryrun-1
    
    Interface text:
    EXPLORER
    DRYRUN-1
    .agents
    .claude
    .codex
    hooks
    sonar-secrets
    sonar-sqaa
    config.toml
    hooks.json
    .scannerwork
    .sonarlint
    .gitignore
    AGENTS.md
    app.py
    apply-sonar.sh
    config.py
    database.py
    README.md
    sonar-project.proper...
    tasks.py
    OUTLINE
    TIMELINE
    app.py
    database.py 1
    ./apply-sonar.sh Untitled-1
    PROBLEMS 1
    OUTPUT
    DEBUG CONSOLE
    TERMINAL
    PORTS
    SONARQUBE 1
    PIXEL AGENTS
    main
    SonarQube
    Killian Carlsen-Phelan (4 days ago)
    Ln 54, Col 30
    Spaces: 4
    UTF-8
    LF
    Python
    3.13.13
    Python 3.13.13

    33:39Demo milestone

  166. 33:40

    Okay.

  167. 33:43

    We're valid. It's looking through all of these. And again, um, running into network connectivity here. This should all happen in a normal, uh, agentic workflow, uh, much quicker than that. Any other questions I can take while we wait for this to, to, to boot up a little bit?

  168. Requesting SonarQube project issues in Codex

    After relaunching Codex, the presenter asks it to list project issues. The terminal reports no MCP tools available and shows Codex still working; no issue list is visible yet.

    Text in image
    def main():
        [lines 30–44 not visible]
            title = sys.argv[2]
            priority = int(sys.argv[3]) if len(sys.argv) > 3 else 0
            add_task(title, priority)
            print(f"Task added: {title}")
    
        elif command == "search":
            if len(sys.argv) < 3:
                print("Usage: python app.py search <query>")
                sys.exit(1)
            results = search_tasks(sys.argv[2])
            print_tasks(results)
    
        elif command == "update":
            handle_update()
    
    Terminal:
    dryrun-1 on main via v3.9.6 took 2m25s
    > codex
    See https://github.com/openai/codex for installation options.
    See full release notes:
    
    OpenAI Codex (v0.142.0)
    model: gpt-5.5 medium /model to change
    directory: ~/dev/dryrun-1
    
    Tip: Run codex app to open Codex Desktop (it installs on macOS if needed).
    > Summarize recent commits
    gpt-5.5 medium · ~/dev/dryrun-1
    
    Interface text:
    EXPLORER
    DRYRUN-1
    .agents
    .claude
    .codex
    hooks
    sonar-secrets
    sonar-sqaa
    config.toml
    hooks.json
    .scannerwork
    .sonarlint
    .gitignore
    AGENTS.md
    app.py
    apply-sonar.sh
    config.py
    database.py
    README.md
    sonar-project.proper...
    tasks.py
    OUTLINE
    TIMELINE
    app.py
    database.py 1
    ./apply-sonar.sh Untitled-1
    PROBLEMS 1
    OUTPUT
    DEBUG CONSOLE
    TERMINAL
    PORTS
    SONARQUBE 1
    PIXEL AGENTS
    main
    SonarQube
    Killian Carlsen-Phelan (4 days ago)
    Ln 54, Col 30
    Spaces: 4
    UTF-8
    LF
    Python
    3.13.13
    Python 3.13.13

    33:52Demo milestone

  169. 34:02

    Is it, uh... I think you can support enterprise or just one of the-

  170. 34:06

    Uh, s- enterprise server?

  171. 34:09

    Sonar, Sonar enterprise.

  172. 34:11

    Yeah, absolutely. This is available across any levels of, of SonarQube use, be that cloud, be that server, be that enterprise, be that the free tier. Um, everybody should have access to this. Now, uh, the limitation there is, uh, context augmentation and agentic analysis are two tools that we do not offer on the free tier. Um, but if you have those entitlements in your org, then you'll be able to use those tools.

  173. 34:41

    All right.

  174. SonarQube issue results

    Codex lists four SonarQube issues in the IDE terminal, including SQL injection risk under S8702. After Sonar reports a secret, Codex says it avoided reading config.py and recommends rotating the key and rerunning analysis.

    Text in image
    SonarQube Issues – kcarlsen-sonarsource_learn-codex-workshop
    
    Found 4 open issue(s):
    
    File | Line | Severity | Rule | Type | Message
    config.py | 7 | Blocker | secrets:S7013 | Vulnerability | OpenAI API key should be revoked, changed, and removed from code.
    database.py | 47 | Critical | python:S5445 | Vulnerability | tempfile.mktemp is insecure; use tempfile.TemporaryFile instead.
    tasks.py | 4 | Critical | python:S3776 | Code Smell | Reduce Cognitive Complexity from 49 to the allowed 15.
    database.py | 39 | Major | pythonsecurity:S8702 | Vulnerability | SQL injection risk from untrusted data in query construction.
    
    Interface text:
    app.py
    29 def main():
    45         title = sys.argv[2]
    46         priority = int(sys.argv[3]) if len(sys.argv) > 3 else 0
    47         add_task(title, priority)
    48         print(f"Task added: {title}")
    50     elif command == "search":
    51         if len(sys.argv) < 3:
    52             print("Usage: python app.py search <query>")
    53             sys.exit(1)
    54         results = search_tasks(sys.argv[2])
    55         print_tasks(results)
    57     elif command == "update":
    58         handle_update()
    
    EXPLORER
    DRYRUN-1
    .agents
    .claude
    .codex
    hooks
    sonar-secrets
    sonar-sqaa
    config.toml
    hooks.json
    .scannerwork
    .sonarlint
    .gitignore
    AGENTS.md
    app.py
    apply-sonar.sh
    config.py
    database.py
    README.md
    sonar-project.proper...
    tasks.py
    OUTLINE
    TIMELINE
    PROBLEMS 1
    OUTPUT
    DEBUG CONSOLE
    TERMINAL
    PORTS
    SONARQUBE 1
    PIXEL AGENTS
    dryrun-1 on main via v3.9.6 took 2m25s
    codex
    Summarize recent commits
    gpt-5.5 medium · ~/dev/dryrun-1

    34:42Demo milestone

    Show 2 builds
    1. 34:42

      Codex lists four SonarQube issues, including a reported exposed key, an insecure temporary file, complexity, and SQL injection risk.

      Text in image
      SonarQube Issues – kcarlsen-sonarsource_learn-codex-workshop
      
      Found 4 open issue(s):
      
      File | Line | Severity | Rule | Type | Message
      config.py | 7 | Blocker | secrets:S7013 | Vulnerability | OpenAI API key should be revoked, changed, and removed from code.
      database.py | 47 | Critical | python:S5445 | Vulnerability | tempfile.mktemp is insecure; use tempfile.TemporaryFile instead.
      tasks.py | 4 | Critical | python:S3776 | Code Smell | Reduce Cognitive Complexity from 49 to the allowed 15.
      database.py | 39 | Major | pythonsecurity:S8702 | Vulnerability | SQL injection risk from untrusted data in query construction.
      
      Interface text:
      app.py
      29 def main():
      45         title = sys.argv[2]
      46         priority = int(sys.argv[3]) if len(sys.argv) > 3 else 0
      47         add_task(title, priority)
      48         print(f"Task added: {title}")
      50     elif command == "search":
      51         if len(sys.argv) < 3:
      52             print("Usage: python app.py search <query>")
      53             sys.exit(1)
      54         results = search_tasks(sys.argv[2])
      55         print_tasks(results)
      57     elif command == "update":
      58         handle_update()
      
      EXPLORER
      DRYRUN-1
      .agents
      .claude
      .codex
      hooks
      sonar-secrets
      sonar-sqaa
      config.toml
      hooks.json
      .scannerwork
      .sonarlint
      .gitignore
      AGENTS.md
      app.py
      apply-sonar.sh
      config.py
      database.py
      README.md
      sonar-project.proper...
      tasks.py
      OUTLINE
      TIMELINE
      PROBLEMS 1
      OUTPUT
      DEBUG CONSOLE
      TERMINAL
      PORTS
      SONARQUBE 1
      PIXEL AGENTS
      dryrun-1 on main via v3.9.6 took 2m25s
      codex
      Summarize recent commits
      gpt-5.5 medium · ~/dev/dryrun-1
    2. 34:45

      A terminal lists four issues, including an exposed secret and SQL injection risk, with a warning to rotate the secret.

      Text in image
      Found 4 open issue(s):
      
      File | Line | Severity | Rule | Type | Message
      config.py | 7 | Blocker | secrets:S7013 | Vulnerability | OpenAI API key should be revoked, changed, and removed from code.
      database.py | 47 | Critical | python:S5445 | Vulnerability | tempfile.mktemp is insecure; use tempfile.TemporaryFile instead.
      tasks.py | 4 | Critical | python:S3776 | Code Smell | Reduce Cognitive Complexity from 49 to the allowed 15.
      database.py | 39 | Major | pythonsecurity:S8702 | Vulnerability | SQL injection risk from untrusted data in query construction.
      
      Important: because Sonar reports a secret in config.py, I did not read that file. Rotate the exposed OpenAI API key at its source, remove it from the file, then re-run analysis.
      
      Worked for 2m 50s
      
      Interface text:
      app.py
      29 def main():
      45         title = sys.argv[2]
      46         priority = int(sys.argv[3]) if len(sys.argv) > 3 else 0
      47         add_task(title, priority)
      48         print(f"Task added: {title}")
      50     elif command == "search":
      51         if len(sys.argv) < 3:
      52             print("Usage: python app.py search <query>")
      53             sys.exit(1)
      54         results = search_tasks(sys.argv[2])
      55         print_tasks(results)
      57     elif command == "update":
      58         handle_update()
      
      EXPLORER
      DRYRUN-1
      .agents
      .claude
      .codex
      hooks
      sonar-secrets
      sonar-sqaa
      config.toml
      hooks.json
      .scannerwork
      .sonarlint
      .gitignore
      AGENTS.md
      app.py
      apply-sonar.sh
      config.py
      database.py
      README.md
      sonar-project.proper...
      tasks.py
      OUTLINE
      TIMELINE
      PROBLEMS 1
      OUTPUT
      DEBUG CONSOLE
      TERMINAL
      PORTS
      SONARQUBE 1
      PIXEL AGENTS
      Summarize recent commits
      gpt-5.5 medium · ~/dev/dryrun-1
  175. 34:45

    So we were able to see that we can get those same issues that we saw on the dashboard now available in the CLI. Imagine that this took fifteen seconds and that the, uh, the, the engineer has a fully connected Wi-Fi connection. Um, they will have this available very quickly within their IDE. Here is the, uh, uh, secret block, uh, blocker severity that I mentioned earlier, but the one that I wanna highlight and get

  176. SonarQube issue results

    Codex lists four SonarQube issues in the IDE terminal, including SQL injection risk under S8702. After Sonar reports a secret, Codex says it avoided reading config.py and recommends rotating the key and rerunning analysis.

    Text in image
    Found 4 open issue(s):
    
    File | Line | Severity | Rule | Type | Message
    config.py | 7 | Blocker | secrets:S7013 | Vulnerability | OpenAI API key should be revoked, changed, and removed from code.
    database.py | 47 | Critical | python:S5445 | Vulnerability | tempfile.mktemp is insecure; use tempfile.TemporaryFile instead.
    tasks.py | 4 | Critical | python:S3776 | Code Smell | Reduce Cognitive Complexity from 49 to the allowed 15.
    database.py | 39 | Major | pythonsecurity:S8702 | Vulnerability | SQL injection risk from untrusted data in query construction.
    
    Important: because Sonar reports a secret in config.py, I did not read that file. Rotate the exposed OpenAI API key at its source, remove it from the file, then re-run analysis.
    
    Worked for 2m 50s
    
    Interface text:
    app.py
    29 def main():
    45         title = sys.argv[2]
    46         priority = int(sys.argv[3]) if len(sys.argv) > 3 else 0
    47         add_task(title, priority)
    48         print(f"Task added: {title}")
    50     elif command == "search":
    51         if len(sys.argv) < 3:
    52             print("Usage: python app.py search <query>")
    53             sys.exit(1)
    54         results = search_tasks(sys.argv[2])
    55         print_tasks(results)
    57     elif command == "update":
    58         handle_update()
    
    EXPLORER
    DRYRUN-1
    .agents
    .claude
    .codex
    hooks
    sonar-secrets
    sonar-sqaa
    config.toml
    hooks.json
    .scannerwork
    .sonarlint
    .gitignore
    AGENTS.md
    app.py
    apply-sonar.sh
    config.py
    database.py
    README.md
    sonar-project.proper...
    tasks.py
    OUTLINE
    TIMELINE
    PROBLEMS 1
    OUTPUT
    DEBUG CONSOLE
    TERMINAL
    PORTS
    SONARQUBE 1
    PIXEL AGENTS
    Summarize recent commits
    gpt-5.5 medium · ~/dev/dryrun-1

    34:52Demo milestone

  177. 35:15

    fixed today is this S8702. This is a rule that we wrote specifically for AI agentic workflows. We do not want AI coding agents to write code that other agents are able to exploit. That is the sys.argv flow that I described a little bit earlier. Again, anybody who has access to sys.argv will be able to have control over your database. We wanna prevent this. So I'm just gonna tell, uh,

  178. 35:45

    Codex, I'm gonna say, "Hey, fis-- fix S8702."

  179. Requesting a fix for S8702

    The presenter asks Codex to fix S8702, the reported SQL injection risk in database.py. Codex is still working; the screen does not yet show a fix.

    Text in image
    app.py
    29  def main():
    45          title = sys.argv[2]
    46          priority = int(sys.argv[3]) if len(sys.argv) > 3 else 0
    47          add_task(title, priority)
    48          print(f"Task added: {title}")
    50      elif command == "search":
    51          if len(sys.argv) < 3:
    52              print("Usage: python app.py search <query>")
    53              sys.exit(1)
    54          results = search_tasks(sys.argv[2])
    55          print_tasks(results)
    57      elif command == "update":
    58          handle_update()
    
    database.py  47  Critical  python:S5445  Vulnerability  tempfile.mktemp is insecure; use tempfile.TemporaryFile instead.
    tasks.py  4  Critical  python:S3776  Code Smell  Reduce Cognitive Complexity from 49 to the allowed 15.
    database.py  39  Major  pythonsecurity:S8702  Vulnerability  SQL injection risk from untrusted data in query construction.
    
    Important: because Sonar reports a secret in config.py, I did not read that file. Rotate the exposed OpenAI API key at its source, remove it from the file, then re-run analysis.
    
    Worked for 2m 50s
    
    fix s8702
    Working (13s · esc to interrupt)
    
    Interface text:
    EXPLORER
    DRYRUN-1
    .agents
    .claude
    .codex
    hooks
    sonar-secrets
    sonar-sqaa
    config.toml
    hooks.json
    .scannerwork
    .sonarlint
    .gitignore
    AGENTS.md
    app.py
    apply-sonar.sh
    config.py
    database.py
    README.md
    sonar-project.proper...
    tasks.py
    OUTLINE
    TIMELINE
    PROBLEMS 1  OUTPUT  DEBUG CONSOLE  TERMINAL  PORTS  SONARQUBE 1  PIXEL AGENTS
    Summarize recent commits
    gpt-5.5 medium · ~/dev/dryrun-1
    main  SonarQube  Killian Carlsen-Phelan (4 days ago)  Ln 54, Col 30  Spaces: 4  UTF-8  LF  Python  3.13.13

    35:52Demo milestone

  180. 35:53

    That's gonna run. And again, all of these issues, you can instantly pull them to your terminal and ask Codex to fix it. There is gonna be something that is different on my machine versus anybody following along, is that as you'll see, as soon as code is edited and changed here, the post tool use hook for agentic analysis will run. What that does is if there were any new vulnerabilities

  181. 36:23

    introduced in the fix, SonarQube will scan it server side. If you do not have agentic analysis, that is totally fine. You can just scan your code, uh, during your next, uh, CI push or anything like that. But, um, regardless, it will get verified. Using agentic analysis just closes that loop and gives you automatic feedback to know that, hey, I have not introduced any more issues. Um, I don't know about y'all, but I have been in,

  182. Preparing the Sonar fix

    Codex scans the Sonar fix skill file for secrets and reads its instructions before investigating the S8702 finding. It also plans to pull project guidelines before editing.

    Text in image
    def main():
        [lines 30–44 not visible]
            title = sys.argv[2]
            priority = int(sys.argv[3]) if len(sys.argv) > 3 else 0
            add_task(title, priority)
            print(f"Task added: {title}")
    
        elif command == "search":
            if len(sys.argv) < 3:
                print("Usage: python app.py search <query>")
                sys.exit(1)
            results = search_tasks(sys.argv[2])
            print_tasks(results)
    
        elif command == "update":
            handle_update()
    
    fix s8702
    
    I’ll use the Sonar fix workflow for pythonsecurity:S8702. Before reading project files, I’ll run the required secret scan; before editing, I’ll also pull the project guidelines from Sonar context.
    
    Ran sonar analyze secrets /Users/killian.carlsenphelan/.codex/plugins/cache/sonar/sonarqube/1.1.0/skills/sonar-fix-issue/SKILL.md
    Secrets scan completed successfully
    
    Explored
    Read SKILL.md (sonarqube:sonar-fix-issue skill)
    
    Working (54s · esc to interrupt)
    
    Interface text:
    dryrun-1
    EXPLORER
    DRYRUN-1
    .agents
    .claude
    .codex
    hooks
    sonar-secrets
    sonar-sqaa
    config.toml
    hooks.json
    .scannerwork
    .sonarlint
    .gitignore
    AGENTS.md
    app.py
    apply-sonar.sh
    config.py
    database.py
    README.md
    sonar-project.proper...
    tasks.py
    app.py > main
    PROBLEMS 1
    OUTPUT
    DEBUG CONSOLE
    TERMINAL
    PORTS
    SONARQUBE 1
    PIXEL AGENTS
    OUTLINE
    TIMELINE
    Summarize recent commits
    gpt-5.5 medium · ~/dev/dryrun-1
    main
    SonarQube
    Killian Carlsen-Phelan (4 days ago)
    Ln 54, Col 30
    Spaces: 4
    UTF-8
    LF
    Python
    3.13.13
    Python 3.13.13

    36:43Demo milestone

  183. Requesting SonarQube project issues in Codex

    After relaunching Codex, the presenter asks it to list project issues. The terminal reports no MCP tools available and shows Codex still working; no issue list is visible yet.

    Text in image
    def main():
        [lines 30–44 not visible]
            title = sys.argv[2]
            priority = int(sys.argv[3]) if len(sys.argv) > 3 else 0
            add_task(title, priority)
            print(f"Task added: {title}")
    
        elif command == "search":
            if len(sys.argv) < 3:
                print("Usage: python app.py search <query>")
                sys.exit(1)
            results = search_tasks(sys.argv[2])
            print_tasks(results)
    
        elif command == "update":
            handle_update()
    
    Terminal:
    dryrun-1 on main via v3.9.6 took 2m25s
    > codex
    See https://github.com/openai/codex for installation options.
    See full release notes:
    
    OpenAI Codex (v0.142.0)
    model: gpt-5.5 medium /model to change
    directory: ~/dev/dryrun-1
    
    Tip: Run codex app to open Codex Desktop (it installs on macOS if needed).
    > Summarize recent commits
    gpt-5.5 medium · ~/dev/dryrun-1
    
    Interface text:
    EXPLORER
    DRYRUN-1
    .agents
    .claude
    .codex
    hooks
    sonar-secrets
    sonar-sqaa
    config.toml
    hooks.json
    .scannerwork
    .sonarlint
    .gitignore
    AGENTS.md
    app.py
    apply-sonar.sh
    config.py
    database.py
    README.md
    sonar-project.proper...
    tasks.py
    OUTLINE
    TIMELINE
    app.py
    database.py 1
    ./apply-sonar.sh Untitled-1
    PROBLEMS 1
    OUTPUT
    DEBUG CONSOLE
    TERMINAL
    PORTS
    SONARQUBE 1
    PIXEL AGENTS
    main
    SonarQube
    Killian Carlsen-Phelan (4 days ago)
    Ln 54, Col 30
    Spaces: 4
    UTF-8
    LF
    Python
    3.13.13
    Python 3.13.13

    36:46Demo milestone

  184. Investigating the SQL injection finding

    After a successful secret scan, Codex reads the SQL injection rule and follows the search call through app.py and database.py. The rule guidance points to parameterized queries.

    Text in image
    app.py
    
    Visible code, line 29:
    def main():
    
    Visible code, lines 45–58:
            title = sys.argv[2]
            priority = int(sys.argv[3]) if len(sys.argv) > 3 else 0
            add_task(title, priority)
            print(f"Task added: {title}")
    
        elif command == "search":
            if len(sys.argv) < 3:
                print("Usage: python app.py search <query>")
                sys.exit(1)
            results = search_tasks(sys.argv[2])
            print_tasks(results)
    
        elif command == "update":
            handle_update()
    
    Ran sonar analyze secrets database.py
    Secrets scan completed successfully
    
    Called sonarqube.show_rule({"key":"pythonsecurity:S8702"})
    {"key": "pythonsecurity:S8702", "name": "Agentic workflows should not be vulnerable to SQL injection attacks", "severity": "MAJOR", "type": "VULNERABILITY", "lang": "py", "langName": "Python", "htmlDesc": "<h2>Why is this an issue?</h2>\n<p>Large Language Models (LLMs) attempt to get out of their diverse sandboxes to get their tasks done, sometimes in ways which could break unexpected\nsystems. In addition to that, malicious users can apply direct or indirect prompt injection techniques, prompting it to use special characters.</p>\n<p>In agentic workflows, these LLMs orchestrate tasks by invoking external tools, including <strong>CLI programs</strong>. For this reason, providing\nunchecked ability to an LLM to make its own database queri...
    
    Working (1m 03s · esc to interrupt)
    
    Interface text:
    EXPLORER
    DRYRUN-1
    .agents
    .claude
    .codex
    hooks
    sonar-secrets
    sonar-sqaa
    config.toml
    hooks.json
    .scannerwork
    .sonarlint
    .gitignore
    AGENTS.md
    app.py
    apply-sonar.sh
    config.py
    database.py
    README.md
    sonar-project.proper...
    tasks.py
    PROBLEMS 1  OUTPUT  DEBUG CONSOLE  TERMINAL  PORTS  SONARQUBE 1  PIXEL AGENTS
    Summarize recent commits
    gpt-5.5 medium · ~/dev/dryrun-1
    main  SonarQube  Killian Carlsen-Phelan (4 days ago)
    Ln 54, Col 30  Spaces: 4  UTF-8  LF  Python  3.13.13

    36:52Demo milestone

    Show 2 builds
    1. 36:52

      Codex reports a successful file scan and displays a SonarQube rule about SQL injection in agentic workflows.

      Text in image
      app.py
      
      Visible code, line 29:
      def main():
      
      Visible code, lines 45–58:
              title = sys.argv[2]
              priority = int(sys.argv[3]) if len(sys.argv) > 3 else 0
              add_task(title, priority)
              print(f"Task added: {title}")
      
          elif command == "search":
              if len(sys.argv) < 3:
                  print("Usage: python app.py search <query>")
                  sys.exit(1)
              results = search_tasks(sys.argv[2])
              print_tasks(results)
      
          elif command == "update":
              handle_update()
      
      Ran sonar analyze secrets database.py
      Secrets scan completed successfully
      
      Called sonarqube.show_rule({"key":"pythonsecurity:S8702"})
      {"key": "pythonsecurity:S8702", "name": "Agentic workflows should not be vulnerable to SQL injection attacks", "severity": "MAJOR", "type": "VULNERABILITY", "lang": "py", "langName": "Python", "htmlDesc": "<h2>Why is this an issue?</h2>\n<p>Large Language Models (LLMs) attempt to get out of their diverse sandboxes to get their tasks done, sometimes in ways which could break unexpected\nsystems. In addition to that, malicious users can apply direct or indirect prompt injection techniques, prompting it to use special characters.</p>\n<p>In agentic workflows, these LLMs orchestrate tasks by invoking external tools, including <strong>CLI programs</strong>. For this reason, providing\nunchecked ability to an LLM to make its own database queri...
      
      Working (1m 03s · esc to interrupt)
      
      Interface text:
      EXPLORER
      DRYRUN-1
      .agents
      .claude
      .codex
      hooks
      sonar-secrets
      sonar-sqaa
      config.toml
      hooks.json
      .scannerwork
      .sonarlint
      .gitignore
      AGENTS.md
      app.py
      apply-sonar.sh
      config.py
      database.py
      README.md
      sonar-project.proper...
      tasks.py
      PROBLEMS 1  OUTPUT  DEBUG CONSOLE  TERMINAL  PORTS  SONARQUBE 1  PIXEL AGENTS
      Summarize recent commits
      gpt-5.5 medium · ~/dev/dryrun-1
      main  SonarQube  Killian Carlsen-Phelan (4 days ago)
      Ln 54, Col 30  Spaces: 4  UTF-8  LF  Python  3.13.13
    2. 36:55

      Codex reviews rule guidance and explores the application and database files.

      Text in image
      app.py
      
      Visible code, line 29:
      def main():
      
      Visible code, lines 45–58:
              title = sys.argv[2]
              priority = int(sys.argv[3]) if len(sys.argv) > 3 else 0
              add_task(title, priority)
              print(f"Task added: {title}")
      
          elif command == "search":
              if len(sys.argv) < 3:
                  print("Usage: python app.py search <query>")
                  sys.exit(1)
              results = search_tasks(sys.argv[2])
              print_tasks(results)
      
          elif command == "update":
              handle_update()
      
      {"key": "pythonsecurity:S8702", "name": "Agentic workflows should not be vulnerable to SQL injection attacks", "severity": "MAJOR", "type": "VULNERABILITY", "lang": "py", "langName": "Python", "htmlDesc": "<h2>Why is this an issue?</h2>\n<p>Large Language Models (LLMs) attempt to get out of their diverse sandboxes to get their tasks done, sometimes in ways which could break unexpected\nsystems. In addition to that, malicious users can apply direct or indirect prompt injection techniques, prompting it to use special characters.</p>\n<p>In agentic workflows, these LLMs orchestrate tasks by invoking external tools, including <strong>CLI programs</strong>. For this reason, providing\nunchecked ability to an LLM to make its own database queri...
      
      The rule guidance points to parameterized queries. The relevant files passed secret scanning, so I’m reading the call path and the database helper now.
      
      Explored
      Read database.py, app.py
      List rg --files
      
      Working (1m 15s · esc to interrupt)
      
      Interface text:
      EXPLORER
      DRYRUN-1
      .agents
      .claude
      .codex
      hooks
      sonar-secrets
      sonar-sqaa
      config.toml
      hooks.json
      .scannerwork
      .sonarlint
      .gitignore
      AGENTS.md
      app.py
      apply-sonar.sh
      config.py
      database.py
      README.md
      sonar-project.proper...
      tasks.py
      PROBLEMS 1  OUTPUT  DEBUG CONSOLE  TERMINAL  PORTS  SONARQUBE 1  PIXEL AGENTS
      Summarize recent commits
      gpt-5.5 medium · ~/dev/dryrun-1
      main  SonarQube  Killian Carlsen-Phelan (4 days ago)
      Ln 54, Col 30  Spaces: 4  UTF-8  LF  Python  3.13.13
  185. 36:53

    uh, coding sessions sometimes where I'm like, "Hey, fix this issue," and then three more kinda pop up, and I'm trying to fix those, and it's like trying to conquer a hydra where they just kinda propagate out. Using this automatically verifies that you're not causing any new, uh, vulnerabilities to come about. Awesome. So we were, we were able to fix this. We get a parameterized query. Wonderful. Um, and this post tool use hook completes. What

  186. Parameterizing the search query

    Codex replaces interpolated SQL with a SQLite placeholder, passing the wildcard-wrapped query as a parameter to preserve substring matching. A post-tool-use hook then runs.

    Text in image
    def main():
        [lines 30–44 not visible]
            title = sys.argv[2]
            priority = int(sys.argv[3]) if len(sys.argv) > 3 else 0
            add_task(title, priority)
            print(f"Task added: {title}")
    
        elif command == "search":
            if len(sys.argv) < 3:
                print("Usage: python app.py search <query>")
                sys.exit(1)
            results = search_tasks(sys.argv[2])
            print_tasks(results)
    
        elif command == "update":
            handle_update()
    
    The vulnerable line builds SQL with an f-string and passes it directly to cursor.execute. I’m changing only that query to use SQLite placeholders while keeping the same substring search behavior.
    
    Edited database.py (+4 -2)
      cursor = conn.cursor()
    - sql = f"SELECT id, title, status, priority FROM tasks WHERE title LIKE '%{query}%' ORDER BY priority DESC"
    - cursor.execute(sql)
    + cursor.execute(
    +     "SELECT id, title, status, priority FROM tasks WHERE title LIKE ? ORDER BY priority DESC",
    +     (f"%{query}%",),
    + )
      results = cursor.fetchall()
    
    Running PostToolUse hook
    Working (1m 22s · esc to interrupt)
    
    Interface text:
    dryrun-1
    EXPLORER
    DRYRUN-1
    .agents
    .claude
    .codex
    hooks
    sonar-secrets
    sonar-sqaa
    config.toml
    hooks.json
    .scannerwork
    .sonarlint
    .gitignore
    AGENTS.md
    app.py
    apply-sonar.sh
    config.py
    database.py
    README.md
    sonar-project.proper...
    tasks.py
    app.py > main
    PROBLEMS 1 · OUTPUT · DEBUG CONSOLE · TERMINAL · PORTS · SONARQUBE 1 · PIXEL AGENTS
    Summarize recent commits
    gpt-5.5 medium · ~/dev/dryrun-1
    OUTLINE · TIMELINE
    main · SonarQube · Killian Carlsen-Phelan (4 days ago) · Ln 54, Col 30 · Spaces: 4 · UTF-8 · LF · Python · 3.13.13

    37:10Demo milestone

  187. 37:23

    it lets you know is, is it lets you know there is an issue in the file, however, that existed beforehand. That was one of the issues that I had already pre-baked in here. So it's not going to try and solve everything else in your file for you. It is smart, and it just realizes that, hey, whatever was in the code that we changed, we're gonna u- uh, analyze that and make sure that there are no new issues introduced from that code. So, wonderful.

  188. Investigating the SQL injection finding

    After a successful secret scan, Codex reads the SQL injection rule and follows the search call through app.py and database.py. The rule guidance points to parameterized queries.

    Text in image
    app.py
    
    Visible code, line 29:
    def main():
    
    Visible code, lines 45–58:
            title = sys.argv[2]
            priority = int(sys.argv[3]) if len(sys.argv) > 3 else 0
            add_task(title, priority)
            print(f"Task added: {title}")
    
        elif command == "search":
            if len(sys.argv) < 3:
                print("Usage: python app.py search <query>")
                sys.exit(1)
            results = search_tasks(sys.argv[2])
            print_tasks(results)
    
        elif command == "update":
            handle_update()
    
    Ran sonar analyze secrets database.py
    Secrets scan completed successfully
    
    Called sonarqube.show_rule({"key":"pythonsecurity:S8702"})
    {"key": "pythonsecurity:S8702", "name": "Agentic workflows should not be vulnerable to SQL injection attacks", "severity": "MAJOR", "type": "VULNERABILITY", "lang": "py", "langName": "Python", "htmlDesc": "<h2>Why is this an issue?</h2>\n<p>Large Language Models (LLMs) attempt to get out of their diverse sandboxes to get their tasks done, sometimes in ways which could break unexpected\nsystems. In addition to that, malicious users can apply direct or indirect prompt injection techniques, prompting it to use special characters.</p>\n<p>In agentic workflows, these LLMs orchestrate tasks by invoking external tools, including <strong>CLI programs</strong>. For this reason, providing\nunchecked ability to an LLM to make its own database queri...
    
    Working (1m 03s · esc to interrupt)
    
    Interface text:
    EXPLORER
    DRYRUN-1
    .agents
    .claude
    .codex
    hooks
    sonar-secrets
    sonar-sqaa
    config.toml
    hooks.json
    .scannerwork
    .sonarlint
    .gitignore
    AGENTS.md
    app.py
    apply-sonar.sh
    config.py
    database.py
    README.md
    sonar-project.proper...
    tasks.py
    PROBLEMS 1  OUTPUT  DEBUG CONSOLE  TERMINAL  PORTS  SONARQUBE 1  PIXEL AGENTS
    Summarize recent commits
    gpt-5.5 medium · ~/dev/dryrun-1
    main  SonarQube  Killian Carlsen-Phelan (4 days ago)
    Ln 54, Col 30  Spaces: 4  UTF-8  LF  Python  3.13.13

    37:29Demo milestone

    Show 2 builds
    1. 36:52

      Codex reports a successful file scan and displays a SonarQube rule about SQL injection in agentic workflows.

      Text in image
      app.py
      
      Visible code, line 29:
      def main():
      
      Visible code, lines 45–58:
              title = sys.argv[2]
              priority = int(sys.argv[3]) if len(sys.argv) > 3 else 0
              add_task(title, priority)
              print(f"Task added: {title}")
      
          elif command == "search":
              if len(sys.argv) < 3:
                  print("Usage: python app.py search <query>")
                  sys.exit(1)
              results = search_tasks(sys.argv[2])
              print_tasks(results)
      
          elif command == "update":
              handle_update()
      
      Ran sonar analyze secrets database.py
      Secrets scan completed successfully
      
      Called sonarqube.show_rule({"key":"pythonsecurity:S8702"})
      {"key": "pythonsecurity:S8702", "name": "Agentic workflows should not be vulnerable to SQL injection attacks", "severity": "MAJOR", "type": "VULNERABILITY", "lang": "py", "langName": "Python", "htmlDesc": "<h2>Why is this an issue?</h2>\n<p>Large Language Models (LLMs) attempt to get out of their diverse sandboxes to get their tasks done, sometimes in ways which could break unexpected\nsystems. In addition to that, malicious users can apply direct or indirect prompt injection techniques, prompting it to use special characters.</p>\n<p>In agentic workflows, these LLMs orchestrate tasks by invoking external tools, including <strong>CLI programs</strong>. For this reason, providing\nunchecked ability to an LLM to make its own database queri...
      
      Working (1m 03s · esc to interrupt)
      
      Interface text:
      EXPLORER
      DRYRUN-1
      .agents
      .claude
      .codex
      hooks
      sonar-secrets
      sonar-sqaa
      config.toml
      hooks.json
      .scannerwork
      .sonarlint
      .gitignore
      AGENTS.md
      app.py
      apply-sonar.sh
      config.py
      database.py
      README.md
      sonar-project.proper...
      tasks.py
      PROBLEMS 1  OUTPUT  DEBUG CONSOLE  TERMINAL  PORTS  SONARQUBE 1  PIXEL AGENTS
      Summarize recent commits
      gpt-5.5 medium · ~/dev/dryrun-1
      main  SonarQube  Killian Carlsen-Phelan (4 days ago)
      Ln 54, Col 30  Spaces: 4  UTF-8  LF  Python  3.13.13
    2. 36:55

      Codex reviews rule guidance and explores the application and database files.

      Text in image
      app.py
      
      Visible code, line 29:
      def main():
      
      Visible code, lines 45–58:
              title = sys.argv[2]
              priority = int(sys.argv[3]) if len(sys.argv) > 3 else 0
              add_task(title, priority)
              print(f"Task added: {title}")
      
          elif command == "search":
              if len(sys.argv) < 3:
                  print("Usage: python app.py search <query>")
                  sys.exit(1)
              results = search_tasks(sys.argv[2])
              print_tasks(results)
      
          elif command == "update":
              handle_update()
      
      {"key": "pythonsecurity:S8702", "name": "Agentic workflows should not be vulnerable to SQL injection attacks", "severity": "MAJOR", "type": "VULNERABILITY", "lang": "py", "langName": "Python", "htmlDesc": "<h2>Why is this an issue?</h2>\n<p>Large Language Models (LLMs) attempt to get out of their diverse sandboxes to get their tasks done, sometimes in ways which could break unexpected\nsystems. In addition to that, malicious users can apply direct or indirect prompt injection techniques, prompting it to use special characters.</p>\n<p>In agentic workflows, these LLMs orchestrate tasks by invoking external tools, including <strong>CLI programs</strong>. For this reason, providing\nunchecked ability to an LLM to make its own database queri...
      
      The rule guidance points to parameterized queries. The relevant files passed secret scanning, so I’m reading the call path and the database helper now.
      
      Explored
      Read database.py, app.py
      List rg --files
      
      Working (1m 15s · esc to interrupt)
      
      Interface text:
      EXPLORER
      DRYRUN-1
      .agents
      .claude
      .codex
      hooks
      sonar-secrets
      sonar-sqaa
      config.toml
      hooks.json
      .scannerwork
      .sonarlint
      .gitignore
      AGENTS.md
      app.py
      apply-sonar.sh
      config.py
      database.py
      README.md
      sonar-project.proper...
      tasks.py
      PROBLEMS 1  OUTPUT  DEBUG CONSOLE  TERMINAL  PORTS  SONARQUBE 1  PIXEL AGENTS
      Summarize recent commits
      gpt-5.5 medium · ~/dev/dryrun-1
      main  SonarQube  Killian Carlsen-Phelan (4 days ago)
      Ln 54, Col 30  Spaces: 4  UTF-8  LF  Python  3.13.13
  189. Fix and verification summary

    Codex replaced the search query’s interpolated input with a SQLite placeholder. The syntax check passed, and the Sonar hook stopped reporting S8702 while still flagging an existing temporary-file issue.

    Text in image
    def main():
        title = sys.argv[2]
        priority = int(sys.argv[3]) if len(sys.argv) > 3 else 0
        add_task(title, priority)
        print(f"Task added: {title}")
    
    elif command == "search":
        if len(sys.argv) < 3:
            print("Usage: python app.py search <query>")
            sys.exit(1)
        results = search_tasks(sys.argv[2])
        print_tasks(results)
    
    elif command == "update":
        handle_update()
    
    Ran git diff — database.py
        diff --git a/database.py b/database.py
        index e43bc66..e597702 100644
        … +13 lines (ctrl + t to view transcript)
            conn.close()
            return results
    
    Fixed pythonsecurity:S8702 in database.py:39. The search query now uses a SQLite placeholder with cursor.execute(..., (f"%{query}%",)) instead of interpolating user-controlled input into the SQL string.
    
    Verification: PYTHONPYCACHEPREFIX=/private/tmp/dryrun-pycache python3 -m py_compile database.py app.py passed. The local Sonar hook no longer reported S8702; it still reports the existing unrelated python:S5445 issue for tempfile.mktemp in database.py.
    
    Worked for 1m 55s
    
    Interface text:
    DRYRUN-1
    EXPLORER
    .agents
    .claude
    .codex
    hooks
    sonar-secrets
    sonar-sqaa
    config.toml
    hooks.json
    .scannerwork
    .sonarlint
    .gitignore
    AGENTS.md
    app.py
    apply-sonar.sh
    config.py
    database.py
    README.md
    sonar-project.proper...
    tasks.py
    PROBLEMS 1
    OUTPUT
    DEBUG CONSOLE
    TERMINAL
    PORTS
    SONARQUBE 1
    PIXEL AGENTS
    Summarize recent commits
    gpt-5.5 medium · ~/dev/dryrun-1
    OUTLINE
    TIMELINE
    main*
    SonarQube
    Killian Carlsen-Phelan (4 days ago)
    Ln 54, Col 30
    Spaces: 4
    UTF-8
    LF
    Python
    3.13.13
    Python 3.13.13

    37:46Demo milestone

  190. Fix and verification summary

    Codex replaced the search query’s interpolated input with a SQLite placeholder. The syntax check passed, and the Sonar hook stopped reporting S8702 while still flagging an existing temporary-file issue.

    Text in image
    def main():
        title = sys.argv[2]
        priority = int(sys.argv[3]) if len(sys.argv) > 3 else 0
        add_task(title, priority)
        print(f"Task added: {title}")
    
    elif command == "search":
        if len(sys.argv) < 3:
            print("Usage: python app.py search <query>")
            sys.exit(1)
        results = search_tasks(sys.argv[2])
        print_tasks(results)
    
    elif command == "update":
        handle_update()
    
    Ran git diff — database.py
        diff --git a/database.py b/database.py
        index e43bc66..e597702 100644
        … +13 lines (ctrl + t to view transcript)
            conn.close()
            return results
    
    Fixed pythonsecurity:S8702 in database.py:39. The search query now uses a SQLite placeholder with cursor.execute(..., (f"%{query}%",)) instead of interpolating user-controlled input into the SQL string.
    
    Verification: PYTHONPYCACHEPREFIX=/private/tmp/dryrun-pycache python3 -m py_compile database.py app.py passed. The local Sonar hook no longer reported S8702; it still reports the existing unrelated python:S5445 issue for tempfile.mktemp in database.py.
    
    Worked for 1m 55s
    
    Interface text:
    DRYRUN-1
    EXPLORER
    .agents
    .claude
    .codex
    hooks
    sonar-secrets
    sonar-sqaa
    config.toml
    hooks.json
    .scannerwork
    .sonarlint
    .gitignore
    AGENTS.md
    app.py
    apply-sonar.sh
    config.py
    database.py
    README.md
    sonar-project.proper...
    tasks.py
    PROBLEMS 1
    OUTPUT
    DEBUG CONSOLE
    TERMINAL
    PORTS
    SONARQUBE 1
    PIXEL AGENTS
    Summarize recent commits
    gpt-5.5 medium · ~/dev/dryrun-1
    OUTLINE
    TIMELINE
    main*
    SonarQube
    Killian Carlsen-Phelan (4 days ago)
    Ln 54, Col 30
    Spaces: 4
    UTF-8
    LF
    Python
    3.13.13
    Python 3.13.13

    37:52Demo milestone

  191. 37:53

    Um, it reanalyzed that code inline and verified that it passed, um, and we no longer report, uh, S8702. So we are able to find and fix and automatically verify, um, new code, uh, as it comes into our workspace. All right.

  192. 38:19

    So I wanna leave a little bit of time for questions at the end, so I'm just gonna, um, move through to this last piece here. And this is, um, adding a new function, right? Delete a task by ID to database.py. And this one, asking it to come up with, uh, new code, it will use context augmentation. As I mentioned earlier, this fetches relevant context, rules, architecture from your project and feeds that into the

  193. Request to delete a task

    The presenter asks the coding agent to add a delete-by-ID function to database.py. He says context augmentation supplies relevant project context, rules, and architecture to the agent.

    Text in image
    database.py
    """Database operations for the task manager."""
    
    import sqlite3
    import tempfile
    from config import DATABASE_PATH
    
    def init_db():
        conn = sqlite3.connect(DATABASE_PATH)
        cursor = conn.cursor()
        cursor.execute("""
            CREATE TABLE IF NOT EXISTS tasks (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                title TEXT NOT NULL,
                status TEXT DEFAULT 'open',
                priority INTEGER DEFAULT 0,
                created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
    
    Fixed pythonsecurity:S8702 in database.py:39. The search query now uses a SQLite placeholder with cursor.execute(..., (f"%{query}%",)) instead of interpolating user-controlled input into the SQL string.
    
    Verification: PYTHONPYCACHEPREFIX=/private/tmp/dryrun-pycache python3 -m py_compile database.py app.py passed. The local Sonar hook no longer reported S8702; it still reports the existing unrelated python:S5445 issue for tempfile.mktemp in database.py.
    
    Worked for 1m 55s
    
    Add a function to delete a task by ID to database.py
    
    Working (10s · esc to interrupt)
    
    Interface text:
    EXPLORER
    DRYRUN-1
    .agents
    .claude
    .codex
    hooks
    sonar-secrets
    sonar-sqaa
    config.toml
    hooks.json
    .scannerwork
    .sonarlint
    .gitignore
    AGENTS.md
    app.py
    apply-sonar.sh
    config.py
    database.py
    README.md
    sonar-project.proper...
    tasks.py
    OUTLINE
    TIMELINE
    PROBLEMS 1
    OUTPUT
    DEBUG CONSOLE
    TERMINAL
    PORTS
    SONARQUBE 1
    PIXEL AGENTS
    Summarize recent commits
    gpt-5.5 medium · ~/dev/dryrun-1
    Ln 42, Col 19
    Spaces: 4
    UTF-8
    LF
    Python 3.13.13

    38:39Demo milestone

  194. 38:49

    agent. Now, I have no idea how long this may take to work. I imagine within less than a few, uh, minutes. Normally, it's seconds. Um, however, what I want you to realize as well is that using this is the full cycle all within the terminal, as we are guiding the agent... Oh, look, it finishes very quickly. Very well done. Um, as we, we, um, get relevant

  195. Scanning the database module

    The secret scan passes, and the agent reads database.py to place the requested delete-by-ID function alongside the existing CRUD helpers.

    Text in image
    database.py
    
    """Database operations for the task manager."""
    
    import sqlite3
    import tempfile
    from config import DATABASE_PATH
    
    def init_db():
        conn = sqlite3.connect(DATABASE_PATH)
        cursor = conn.cursor()
        cursor.execute("""
            CREATE TABLE IF NOT EXISTS tasks (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                title TEXT NOT NULL,
                status TEXT DEFAULT 'open',
                priority INTEGER DEFAULT 0,
                created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
    
    +3 lines (ctrl + t to view transcript)
    4. Python: Cognitive Complexity of functions should not be too high
    
    Ran sonar analyze secrets database.py
      Secrets scan completed successfully
    
    database.py passed secret scanning. I’m reading the file now to place the function alongside the existing CRUD-style helpers.
    
    Explored
      Read database.py
    
    Working (20s · esc to interrupt)
    
    Interface text:
    dryrun-1
    EXPLORER
    DRYRUN-1
    .agents
    .claude
    .codex
      hooks
        sonar-secrets
        [illegible]
      config.toml
      hooks.json
    .scannerwork
    .sonarlint
    .gitignore
    AGENTS.md
    app.py
    apply-sonar.sh
    config.py
    database.py
    README.md
    sonar-project.proper...
    tasks.py
    OUTLINE
    TIMELINE
    app.py
    database.py 1, M
    ./apply-sonar.sh
    Untitled-1
    database.py > search_tasks
    PROBLEMS 1
    OUTPUT
    DEBUG CONSOLE
    TERMINAL
    PORTS
    SONARQUBE 1
    PIXEL AGENTS
    Summarize recent commits
    gpt-5.5 medium · ~/dev/dryrun-1
    main*
    SonarQube
    Killian Carlsen-Phelan (4 days ago)
    Ln 42, Col 19
    Spaces: 4
    UTF-8
    LF
    Python
    3.13.13
    Python 3.13.13

    38:52Demo milestone

  196. Task deletion and hook finding

    Codex adds a parameterized task deletion function. The post-tool analysis hook then flags an insecure tempfile.mktemp call on line 60.

    Text in image
    Editor excerpt (clipped):
    database.py
    
    """Database operations for the task manager."""
    
    import sqlite3
    import tempfile
    from config import DATABASE_PATH
    
    def init_db():
        conn = sqlite3.connect(DATABASE_PATH)
        cursor = conn.cursor()
        cursor.execute("""
            CREATE TABLE IF NOT EXISTS tasks (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                title TEXT NOT NULL,
                status TEXT DEFAULT 'open',
                priority INTEGER DEFAULT 0,
                created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
    
    Terminal diff excerpt:
    +    cursor.execute("DELETE FROM tasks WHERE id = ?", (task_id,))
    +    deleted = cursor.rowcount > 0
    +    conn.commit()
    +    conn.close()
    +    return deleted
    +
    +
     def search_tasks(query):
    
    PostToolUse hook (completed)
    hook context: ! database.py - 1 issue
    [1] line 60 'tempfile.mktemp' is insecure. Use 'tempfile.TemporaryFile' instead  python:S5445
    1 files analyzed - 1 with issues - 1 issue found
    Working (26s • esc to interrupt)
    
    Interface text:
    EXPLORER
    DRYRUN-1
    .agents
    .claude
    .codex
    hooks
    sonar-secrets
    sonar-sqaa
    config.toml
    hooks.json
    .scannerwork
    .sonarlint
    .gitignore
    AGENTS.md
    app.py
    apply-sonar.sh
    config.py
    database.py
    README.md
    sonar-project.proper...
    tasks.py
    OUTLINE
    TIMELINE
    PROBLEMS 1
    OUTPUT
    DEBUG CONSOLE
    TERMINAL
    PORTS
    SONARQUBE 1
    PIXEL AGENTS
    Summarize recent commits
    gpt-5.5 medium · ~/dev/dryrun-1
    SonarQube
    Killian Carlsen-Phelan (4 days ago)
    Ln 53, Col 19
    Spaces: 4
    UTF-8
    LF
    Python
    3.13.13

    39:03Demo milestone

  197. 39:18

    context, um, we u- we get this to be fixed, uh, or implemented in this case when we're asking it to implement a new, uh, feature. It gets verified from the, uh, agentic analysis hook, and if there were any issues in there, uh, they would be flagged, and Codex would continue to iterate until it is remediated. So that's how we're getting that guide, verify, and solve, uh, methodology in here. All right.

  198. Task deletion and hook finding

    Codex adds a parameterized task deletion function. The post-tool analysis hook then flags an insecure tempfile.mktemp call on line 60.

    Text in image
    Editor excerpt (clipped):
    database.py
    
    """Database operations for the task manager."""
    
    import sqlite3
    import tempfile
    from config import DATABASE_PATH
    
    def init_db():
        conn = sqlite3.connect(DATABASE_PATH)
        cursor = conn.cursor()
        cursor.execute("""
            CREATE TABLE IF NOT EXISTS tasks (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                title TEXT NOT NULL,
                status TEXT DEFAULT 'open',
                priority INTEGER DEFAULT 0,
                created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
    
    Terminal excerpt:
    not found."
    
    Terminal diff excerpt:
    +def delete_task(task_id):
    +    """Delete a task by ID. Return True if a task was deleted."""
    +    conn = sqlite3.connect(DATABASE_PATH)
    +    cursor = conn.cursor()
    +    cursor.execute("DELETE FROM tasks WHERE id = ?", (task_id,))
    +    deleted = cursor.rowcount > 0
    +    conn.commit()
    +    conn.close()
    +    return deleted
    +
    +
     def search_tasks(query):
    
    PostToolUse hook (completed)
    hook context: ! database.py - 1 issue
    [1] line 60 'tempfile.mktemp' is insecure. Use 'tempfile.TemporaryFile' instead  python:S5445
    1 files analyzed - 1 with issues - 1 issue found
    
    Interface text:
    EXPLORER
    DRYRUN-1
    .agents
    .claude
    .codex
    hooks
    sonar-secrets
    sonar-sqaa
    config.toml
    hooks.json
    .scannerwork
    .sonarlint
    .gitignore
    AGENTS.md
    app.py
    apply-sonar.sh
    config.py
    database.py
    README.md
    sonar-project.proper...
    tasks.py
    OUTLINE
    TIMELINE
    PROBLEMS 1
    OUTPUT
    DEBUG CONSOLE
    TERMINAL
    PORTS
    SONARQUBE 1
    PIXEL AGENTS
    SonarQube
    Killian Carlsen-Phelan (4 days ago)
    Ln 53, Col 19
    Spaces: 4
    UTF-8
    LF
    Python
    3.13.13

    39:23Demo milestone

  199. Completed task deletion and verification

    Codex reports adding parameterized task deletion and passing a syntax check. The Sonar hook still reports an existing, unrelated tempfile.mktemp issue.

    Text in image
    """Database operations for the task manager."""
    
    import sqlite3
    import tempfile
    from config import DATABASE_PATH
    
    def init_db():
        conn = sqlite3.connect(DATABASE_PATH)
        cursor = conn.cursor()
        cursor.execute("""
            CREATE TABLE IF NOT EXISTS tasks (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                title TEXT NOT NULL,
                status TEXT DEFAULT 'open',
                priority INTEGER DEFAULT 0,
                created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
    
    diff --git a/database.py b/database.py
    index [illegible] 100644
    +28 lines (ctrl + t to view transcript)
        conn.close()
        return results
    
    Added delete_task(task_id) to database.py:34. It uses a parameterized DELETE FROM tasks WHERE id = ?, commits the change, closes the connection, and returns True only when a row was deleted.
    
    Verification passed: PYTHONPYCACHEPREFIX=/private/tmp/dryrun-pycache python3 -m py_compile database.py.
    
    Note: the Sonar hook still reports the existing unrelated python:S5445 issue for tempfile.mktemp.
    
    Interface text:
    dryrun-1
    EXPLORER
    DRYRUN-1
    .agents
    .claude
    .codex
    hooks
    sonar-secrets
    sonar-sqaa
    config.toml
    hooks.json
    .scannerwork
    .sonarlint
    .gitignore
    AGENTS.md
    app.py
    apply-sonar.sh
    config.py
    database.py
    README.md
    sonar-project.proper...
    tasks.py
    app.py
    database.py 1, M
    ./apply-sonar.sh Untitled-1
    database.py > search_tasks
    PROBLEMS 1
    OUTPUT
    DEBUG CONSOLE
    TERMINAL
    PORTS
    SONARQUBE 1
    PIXEL AGENTS
    Summarize recent commits
    gpt-5.5 medium · ~/dev/dryrun-1
    OUTLINE
    TIMELINE
    main
    SonarQube
    Killian Carlsen-Phelan (4 days ago)
    Ln 53, Col 19
    Spaces: 4
    UTF-8
    LF
    Python
    3.13.13
    Python 3.13.13

    39:45Demo milestone

  200. 39:49

    I'm not gonna spend any more time in the terminal. Um, this again is available for you to work on, uh, at your own leisure. Uh, there's a couple more things in there that you can do like, um, go ahead and track down some of the remaining issues, um, if your org has entitlement for context augmentation and agentic analysis, uh, using that a little bit. Um, but we are able to see that secrets get blocked, right? We can do find and fix on issues that

  201. Completed task deletion and verification

    Codex reports adding parameterized task deletion and passing a syntax check. The Sonar hook still reports an existing, unrelated tempfile.mktemp issue.

    Text in image
    """Database operations for the task manager."""
    
    import sqlite3
    import tempfile
    from config import DATABASE_PATH
    
    def init_db():
        conn = sqlite3.connect(DATABASE_PATH)
        cursor = conn.cursor()
        cursor.execute("""
            CREATE TABLE IF NOT EXISTS tasks (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                title TEXT NOT NULL,
                status TEXT DEFAULT 'open',
                priority INTEGER DEFAULT 0,
                created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
    
    diff --git a/database.py b/database.py
    index [illegible] 100644
    +28 lines (ctrl + t to view transcript)
        conn.close()
        return results
    
    Added delete_task(task_id) to database.py:34. It uses a parameterized DELETE FROM tasks WHERE id = ?, commits the change, closes the connection, and returns True only when a row was deleted.
    
    Verification passed: PYTHONPYCACHEPREFIX=/private/tmp/dryrun-pycache python3 -m py_compile database.py.
    
    Note: the Sonar hook still reports the existing unrelated python:S5445 issue for tempfile.mktemp.
    
    Interface text:
    dryrun-1
    EXPLORER
    DRYRUN-1
    .agents
    .claude
    .codex
    hooks
    sonar-secrets
    sonar-sqaa
    config.toml
    hooks.json
    .scannerwork
    .sonarlint
    .gitignore
    AGENTS.md
    app.py
    apply-sonar.sh
    config.py
    database.py
    README.md
    sonar-project.proper...
    tasks.py
    app.py
    database.py 1, M
    ./apply-sonar.sh Untitled-1
    database.py > search_tasks
    PROBLEMS 1
    OUTPUT
    DEBUG CONSOLE
    TERMINAL
    PORTS
    SONARQUBE 1
    PIXEL AGENTS
    Summarize recent commits
    gpt-5.5 medium · ~/dev/dryrun-1
    OUTLINE
    TIMELINE
    main
    SonarQube
    Killian Carlsen-Phelan (4 days ago)
    Ln 53, Col 19
    Spaces: 4
    UTF-8
    LF
    Python
    3.13.13
    Python 3.13.13

    39:52Demo milestone

  202. 40:19

    exist, and the new tasks that we're having it do, uh, have a much stricter verification layer wrapped around it. And thank you very much for wading through some of the network connectivity issues with this. Um, I wanna say that we at Sonar have a booth downstairs. I would love, uh, to come and talk to any of you guys. Would love to chat about either AI-related coding or anything outside of that. Uh, feel more than free to come

  203. 40:49

    out and say hi to us. We have swag. We have Guitar Hero. We are, we are, um, having a party down there. Um, our, uh, community that we have, our Sonar community, I believe it's community.sonarsource.com, is a great resource if you get stuck working through the repo at all in your own time. Um, that is where our engineers who build the product are able to answer questions and, and help people along, um, who, who run into issues.

  204. Completed task deletion and verification

    Codex reports adding parameterized task deletion and passing a syntax check. The Sonar hook still reports an existing, unrelated tempfile.mktemp issue.

    Text in image
    """Database operations for the task manager."""
    
    import sqlite3
    import tempfile
    from config import DATABASE_PATH
    
    def init_db():
        conn = sqlite3.connect(DATABASE_PATH)
        cursor = conn.cursor()
        cursor.execute("""
            CREATE TABLE IF NOT EXISTS tasks (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                title TEXT NOT NULL,
                status TEXT DEFAULT 'open',
                priority INTEGER DEFAULT 0,
                created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
    
    diff --git a/database.py b/database.py
    index [illegible] 100644
    +28 lines (ctrl + t to view transcript)
        conn.close()
        return results
    
    Added delete_task(task_id) to database.py:34. It uses a parameterized DELETE FROM tasks WHERE id = ?, commits the change, closes the connection, and returns True only when a row was deleted.
    
    Verification passed: PYTHONPYCACHEPREFIX=/private/tmp/dryrun-pycache python3 -m py_compile database.py.
    
    Note: the Sonar hook still reports the existing unrelated python:S5445 issue for tempfile.mktemp.
    
    Interface text:
    dryrun-1
    EXPLORER
    DRYRUN-1
    .agents
    .claude
    .codex
    hooks
    sonar-secrets
    sonar-sqaa
    config.toml
    hooks.json
    .scannerwork
    .sonarlint
    .gitignore
    AGENTS.md
    app.py
    apply-sonar.sh
    config.py
    database.py
    README.md
    sonar-project.proper...
    tasks.py
    app.py
    database.py 1, M
    ./apply-sonar.sh Untitled-1
    database.py > search_tasks
    PROBLEMS 1
    OUTPUT
    DEBUG CONSOLE
    TERMINAL
    PORTS
    SONARQUBE 1
    PIXEL AGENTS
    Summarize recent commits
    gpt-5.5 medium · ~/dev/dryrun-1
    OUTLINE
    TIMELINE
    main
    SonarQube
    Killian Carlsen-Phelan (4 days ago)
    Ln 53, Col 19
    Spaces: 4
    UTF-8
    LF
    Python
    3.13.13
    Python 3.13.13

    40:52Demo milestone

  205. 41:19

    But thank you very much for, uh, listening and working along with me. And if you guys have any questions, uh, feel free to come up or raise your hand, and we can work through that. Well, again, thank you very much for coming. My name is Killian, uh, with Sonar, and, uh, hope to see you down at the booth. Appreciate it.