QDivZero — Laboratorio de ciberseguridad / Cybersecurity lab
Python 3.11+, standard library only. All customer and SSH data is fictional.

1. Extract the ZIP and open a terminal in the extracted folder.
2. Deploy and start the model following the guide. Use ciberseguridad-qwen as
   the serving name, or set QDIV0_MODEL to your chosen name.
3. Export your own credentials, then run the exercises:

   export QDIV0_API_KEY='YOUR_API_KEY'
   export QDIV0_ACCOUNT_ID='YOUR_ACCOUNT_ID'
   python3 review_security.py --case redteam --output results/redteam.json
   python3 sql_lab.py
   python3 review_security.py --case php-counter --output results/php.json
   python3 review_security.py --case logs --output results/ssh.json

The default requested answer language is Spanish. Add --language en for English.
The account ID is X-Account-Id under Developers → View code.
Requests go to https://api.qdiv0.com/v1/chat/completions.

FILES
review_security.py          Sends one case and saves the request and response.
cases/code_review.py.txt    Vulnerable and parameterized customer lookups.
sql_lab.py                  Runs both lookups against local in-memory SQLite.
cases/ssh_events.log        Seven fictional SSH authentication events.
cases/php82_session_excerpt.c.txt  Selected original PHP 8.2.34 C/header lines.
cases/php82_source.json      Source checksum and original excerpt locations.
cases/PHP-LICENSE.txt        PHP source license.
php-counter-proposal.patch  Model proposal with corrected diff formatting.
reference.md                Human-written explanation of the expected findings.
prompts/*.txt               Exact Spanish user messages used in the live tests.
model-outputs/*.md          Unedited answers copied from QDivZero's chat.
model-outputs/*observations.json  Parameters and provenance for those answers.

RED TEAM
The model receives the two lookup functions and a request for a minimal SQL
injection proof. sql_lab.py independently runs the included proof against
Alice and O'Connor. Expected output: vulnerable_rows 2, parameterized_rows 0.
The lab also asserts that a legitimate apostrophe lookup works and a missing
name returns no rows. The SQLite database exists only in memory.

BLUE TEAM
The model receives ssh_events.log and a request for a timeline, observed facts,
hypotheses and missing evidence. reference.md explains what the log establishes.
The four failures and later backup login do not prove a compromise.

PHP REVIEW
--case php-counter sends the original C excerpts plus the reproduced stale counter
symptom. It does not send the reference patch or reported vulnerability identifiers.
An earlier neutral --case php review failed to establish a valid defect. Both
unedited answers are retained. The second answer identifies the stale pointer
following array separation, but includes unsupported parser speculation. Its diff
required indentation, hunk counts and source-line corrections. The three added C
statements are unchanged. The normalized proposal was compiled as session.so in a
matching local SDK and tested separately from php-liferaft's independent patch.
php-regression.json records those functional results; no RCE chain was tested.
The C excerpt is not a standalone file to compile. See the linked php-liferaft
project for its source build and regression environment.

This product includes PHP software, freely available from https://www.php.net/software/
The bundled PHP excerpts and derived patch retain the PHP License 3.01 in
cases/PHP-LICENSE.txt. Excerpts are selected from the original release archive.

An optional --case code request asks for a code review of the same SQL fixture.
Its saved model answer contains an inadequate regression test; see reference.md.

REQUESTS AND OUTPUTS
The client sends exactly one user message, no system/developer message or tools.
Defaults: temperature 0.2, max_tokens 3072, reasoning_effort none, stream false.
The fixture is encoded as a JSON array of numbered lines, preserving indentation.
It prints the final answer and saves the exact request, server response, elapsed
request time and truncation flag. It does not execute the model's proposed code.
Credentials are sent in HTTP headers and are not stored in the output JSON.

Choose a new output filename for each request. Existing files block the request.
HTTP failures and timeouts are not automatically retried. Check deployment status
before trying again. If finish_reason is length, the partial answer is saved and
the client prints a warning. Inspect the saved text before using the result.

LIVE TESTS
The bundled Markdown answers came from real requests in QDivZero's chat, using
the bundled Spanish prompts and direct answers (thinking disabled). The Python
client was tested with a local HTTP server; it was not used for those live runs.
The local sql_lab.py proof and PHP FastCGI regressions were executed separately. These are integration examples,
not a cybersecurity benchmark or a concurrency test.

request_seconds includes network transfer, gateway wait and model generation.
It excludes model startup and time between requests. Whole-session compute cost
also includes billed startup and idle time. Stop the deployment when finished
and wait for its Stopped status.
