Trigger icon
Script icon
Loop icon
ChatCompletion icon
Anthropic icon
SlackIncomingWebhook icon
If icon
Pause icon
Upload icon
Set icon

Security Questionnaire Autopilot with Cited Answers, an Approved-Answer Library and Human Review

Answer vendor security questionnaires from your own policies with verified citations, reuse approved answers, and review only uncertain ones.

Categories
AIBusiness

Every B2B deal brings a security questionnaire: SIG, CAIQ or a custom spreadsheet with 50 to 300 questions. Answering one takes the security team 6 to 40 hours, mostly by finding the same facts in the same policies again. This blueprint answers questionnaires from your own policy documents. It reuses every answer your team approved before, drafts the rest with an LLM that must cite the policy section it used, and sends only uncertain answers to a person. It's for security, compliance and sales engineering teams at B2B SaaS companies.

How it works

  1. A questionnaire (.xlsx or .csv) dropped into s3://<bucket>/questionnaires/inbox/ starts a run through new_questionnaire (io.kestra.plugin.aws.s3.Trigger), which moves the file to questionnaires/processing/. You can also upload one when running the flow manually.
  2. read_questions (io.kestra.plugin.scripts.python.Script) finds the question column, even below title rows. Questions already in the approved answer library (KV store) are answered from it without a model call, and the rest are split into batches.
  3. load_policies reads your policy documents from Kestra namespace files under security-policies/ (Markdown or text) and gives every section a citation id such as data-protection#1.
  4. draft_answers (io.kestra.plugin.core.flow.Loop, three batches at a time) asks io.kestra.plugin.ai.completion.ChatCompletion with Anthropic to answer only from those sections, with an answer, explanation, citations and confidence. The policies are the same for every batch, so prompt caching keeps the cost down.
  5. assemble checks every citation against the real section ids. An answer goes to review when it cites a section that doesn't exist, has no valid citation, is Unknown, or is below confidence_threshold. It writes the completed spreadsheet (your original columns plus Answer, Explanation, Sources, Confidence and Status) and review.csv, which holds only the answers to check.
  6. post_summary posts the counts to Slack. Outside a dry run, ask_reviewer points the security team at review.csv, and approval (io.kestra.plugin.core.flow.Pause) waits for the corrected file to be uploaded, or for a plain approval. Without a decision within seven days, the execution is cancelled.
  7. On approval, apply_corrections merges the reviewer's answers and writes the final spreadsheet, upload_answers (io.kestra.plugin.aws.s3.Upload) stores it in questionnaires/answered/, and grow_library (io.kestra.plugin.core.kv.Set) adds every approved answer to the library, so the next questionnaire needs fewer model calls and less review. alert_failure posts any failure to Slack.

Question text travels as base64 between tasks, so nothing in a customer's spreadsheet is ever evaluated as a Kestra expression.

Prerequisites

  • Your security policies as Markdown or text files in this flow's namespace files under security-policies/. Use ## headings for sections, because each heading becomes a citable section.
  • An S3-compatible bucket (AWS S3, MinIO, SeaweedFS, R2 and others) with a questionnaires/ folder, set in the bucket, s3_endpoint and region variables.
  • Docker on the worker for the Python script tasks.
  • Secrets:
    • S3_ACCESS_KEY_ID and S3_SECRET_KEY_ID: credentials to read the inbox, move files and write questionnaires/answered/.
    • ANTHROPIC_API_KEY: Anthropic API key for drafting answers.
    • SLACK_WEBHOOK_URL: Slack incoming webhook for the summary, the review request, the completion message and failure alerts.

Inputs

  • questionnaire (FILE, optional): an .xlsx or .csv file for manual runs.
  • question_column (STRING, optional): the exact header of the question column. Empty means the first header containing "question".
  • confidence_threshold (INT, default 70): drafted answers below this go to review.
  • batch_size (INT, default 15): questions per model call.
  • dry_run (BOOL, default true): draft and report only. No review request, nothing written to the bucket, and the library is unchanged.

Quick start

  1. Upload your policies to the namespace files under security-policies/, set the bucket variables, and add the four secrets.
  2. Run the flow manually, upload a questionnaire, and keep dry_run on. Download answered.xlsx and review.csv from the assemble outputs.
  3. Run it again with dry_run set to false, fill final_answer and final_explanation in review.csv where needed, upload it in the paused execution, and approve.
  4. Enable the new_questionnaire trigger so questionnaires dropped into the inbox are answered automatically.

Outputs

  • {{ outputs.answered_file }} / {{ outputs.assemble.outputFiles['answered.xlsx'] }}: the questionnaire with drafted answers, sources, confidence and status.
  • {{ outputs.review_file }} / {{ outputs.assemble.outputFiles['review.csv'] }}: only the answers that need a person, with the reason for each.
  • {{ outputs.needs_review }} and {{ outputs.assemble.vars.counts }}: answers from the library, drafted with sources, and needing review.
  • {{ outputs.apply_corrections.outputFiles['final.xlsx'] }}: the final questionnaire, also stored as questionnaires/answered/<name>-answered.xlsx.
  • KV key questionnaire-answer-library: every approved answer, keyed by the normalized question.

Common pitfalls

  • Answers are only as good as the policies. Questions the policies don't cover come back Unknown and always go to review. Add a policy section, and the next questionnaire answers them.
  • The library matches questions after normalizing case and punctuation. Reworded questions are drafted again, with citations.
  • Very large policy sets increase the prompt size. Split the policies by topic into separate namespace folders if needed.
  • Set the claude_model variable to change the model.

How to extend

  • Export the final answers to your trust portal or CRM with an HTTP task after upload_answers.
  • Add a namespace file of approved standard answers (for example legal entity details) and load it into the library.
  • Route review by topic to different owners using the citation prefixes.

Links

See How

New to Kestra?

Use blueprints to kickstart your first workflows.