Skip to content

Python: docs: add Vaultak runtime security integration (filter sample + guide)#14043

Open
samueloladji-beep wants to merge 3 commits into
microsoft:mainfrom
samueloladji-beep:docs/vaultak-security
Open

Python: docs: add Vaultak runtime security integration (filter sample + guide)#14043
samueloladji-beep wants to merge 3 commits into
microsoft:mainfrom
samueloladji-beep:docs/vaultak-security

Conversation

@samueloladji-beep
Copy link
Copy Markdown

Summary

  • Adds docs/VAULTAK_SECURITY.md — a concise integration guide explaining how to wire Vaultak into Semantic Kernel using the native filter system, with a quick-start snippet, configuration table, and event-coverage table.
  • Adds python/samples/concepts/filtering/vaultak_security_filter.py — a runnable end-to-end sample (MathPlugin + TimePlugin) demonstrating both filter types.

Integration pattern: Vaultak registers as a FunctionInvocationFilter and an AutoFunctionInvocationFilter. Every plugin function call is risk-scored (0–10) before it executes; calls above the threshold raise KernelFunctionCancelledError (explicit invocations) or set context.terminate = True (auto function calling). Plugin outputs are passed through mask_pii() before they propagate to the next step.

@kernel.filter(FilterTypes.FUNCTION_INVOCATION)
async def vaultak_function_filter(context, next):
    result = vt.score_action(action=f"{plugin}-{fn}", context=dict(context.arguments))
    if result.score >= RISK_THRESHOLD:
        raise KernelFunctionCancelledError(f"[Vaultak] blocked — risk {result.score:.1f}/10")
    vt.check_policy(tool_name=..., input_data=...)
    await next(context)
    context.result._value = vt.mask_pii(str(context.result.value))

@kernel.filter(FilterTypes.AUTO_FUNCTION_INVOCATION)
async def vaultak_auto_filter(context, next):
    result = vt.score_action(action=f"{plugin}-{fn}", context={"auto_invoke": "true"})
    if result.score >= RISK_THRESHOLD:
        context.terminate = True
        return
    await next(context)

Install

pip install vaultak semantic-kernel

Get an API key at vaultak.com.

Test plan

  • Run python/samples/concepts/filtering/vaultak_security_filter.py with OPENAI_API_KEY and VAULTAK_API_KEY set
  • Verify MathPlugin and TimePlugin calls are intercepted by both filters
  • Confirm that raising KernelFunctionCancelledError surfaces cleanly to the caller
  • Review docs/VAULTAK_SECURITY.md renders correctly on GitHub

🤖 Generated with Claude Code

Adds a security integration guide and a runnable Python sample showing
how to wire Vaultak into Semantic Kernel using the native filter system
(FunctionInvocationFilter + AutoFunctionInvocationFilter). Every plugin
call is risk-scored before execution and PII is masked in outputs.

- docs/VAULTAK_SECURITY.md — integration guide with quick-start,
  configuration table, event-coverage table, and links
- python/samples/concepts/filtering/vaultak_security_filter.py —
  end-to-end sample with MathPlugin and TimePlugin

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@samueloladji-beep samueloladji-beep requested a review from a team as a code owner May 29, 2026 18:40
Copilot AI review requested due to automatic review settings May 29, 2026 18:40
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Adds a runnable example and documentation for integrating Vaultak runtime security with Semantic Kernel filters to risk-score, enforce policy, and mask PII during tool/function invocation.

Changes:

  • Added a Python sample demonstrating FunctionInvocationFilter and AutoFunctionInvocationFilter with Vaultak scoring, policy checks, and output masking.
  • Added documentation describing the integration, setup, and a “quick start” code snippet.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 8 comments.

File Description
python/samples/concepts/filtering/vaultak_security_filter.py New end-to-end sample wiring Vaultak into SK filters and demonstrating a short conversation.
docs/VAULTAK_SECURITY.md New integration guide explaining Vaultak + SK filters with install steps and quick start snippet.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

# Collect function arguments as context for the risk scorer
args_context = {k: str(v) for k, v in (context.arguments or {}).items()}

result = vt.score_action(action=action, context=args_context)
)

# Check against configured policy rules
vt.check_policy(tool_name=action, input_data=str(args_context))
# Scan the function output for PII before it propagates
if context.result and context.result.value:
raw_output = str(context.result.value)
context.result._value = vt.mask_pii(raw_output)
Comment on lines +70 to +74
if result.score >= RISK_THRESHOLD:
raise KernelFunctionCancelledError(
f"[Vaultak] Function '{action}' blocked — risk score {result.score:.1f}/10 "
f"exceeds threshold {RISK_THRESHOLD}. Review at app.vaultak.com"
)
Comment on lines +39 to +42
VAULTAK_API_KEY = os.environ.get("VAULTAK_API_KEY", "vtk_...")
RISK_THRESHOLD = 7.0 # Block function calls with a risk score >= this value

vt = Vaultak(api_key=VAULTAK_API_KEY, agent_name="sk-agent")
Comment thread docs/VAULTAK_SECURITY.md
context: FunctionInvocationContext,
next: Callable[[FunctionInvocationContext], Coroutine[Any, Any, None]],
) -> None:
action = f"{context.function.plugin_name}-{context.function.name}"
Comment thread docs/VAULTAK_SECURITY.md Outdated
vt.check_policy(tool_name=action, input_data=str(context.arguments))
await next(context)
if context.result and context.result.value:
context.result._value = vt.mask_pii(str(context.result.value))
Comment thread docs/VAULTAK_SECURITY.md
| `kernel.invoke()` (explicit call) | Risk-scores the plugin + function; blocks if above threshold |
| Auto function call selected by LLM | Risk-scores; terminates auto-invocation loop if above threshold |
| Plugin output returned | Scans for PII and masks before the result propagates |
| Policy check fails | Raises exception with dashboard URL |
@moonbox3 moonbox3 added python Pull requests for the Python Semantic Kernel documentation labels May 29, 2026
@github-actions github-actions Bot changed the title docs: add Vaultak runtime security integration (filter sample + guide) Python: docs: add Vaultak runtime security integration (filter sample + guide) May 29, 2026
- Wrap synchronous vt.score_action(), vt.check_policy(), and
  vt.mask_pii() calls with asyncio.to_thread() to avoid blocking
  the event loop
- Replace context.result._value (private attr) with the public
  FunctionResult constructor: context.result = FunctionResult(...)
- Update threshold error messages to say "meets or exceeds" to
  accurately reflect the >= operator
- Raise ValueError when VAULTAK_API_KEY env var is missing instead
  of silently defaulting to a placeholder string
- Fix plugin_name None fallback in docs quick start to use
  `or 'kernel'` consistent with the sample file
- Add dashboard URL to exception message in docs quick start snippet

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@samueloladji-beep
Copy link
Copy Markdown
Author

@microsoft-github-policy-service agree

Copy link
Copy Markdown
Contributor

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated Code Review

Reviewers: 4 | Confidence: 95%

✗ Correctness

The sample file imports KernelFunctionCancelledError from semantic_kernel.exceptions, but this class does not exist anywhere in the Semantic Kernel Python package. The only cancellation-related exception is OperationCancelledException. This will cause an ImportError at module load time, making the sample completely non-functional. The same non-existent import appears in the documentation quick-start snippet.

✓ Security Reliability

The sample and docs import KernelFunctionCancelledError which does not exist in the semantic_kernel.exceptions module (verified: only OperationCancelledException exists), causing an ImportError at load time. Additionally, the PII masking via context.result._value = ... is silently non-functional: FunctionResult is a Pydantic v2 model where the field is value, not _value; setting _value creates an unused attribute without changing the result propagated downstream. This means the advertised PII protection does not actually work.

✓ Test Coverage

This PR adds a Vaultak security filter sample and documentation but provides zero test coverage. Every other filtering sample in python/samples/concepts/filtering/ is registered in python/tests/samples/test_concepts.py as a parameterized integration test case. The new vaultak_security_filter.py is not added there, nor does it have any unit tests with mocked Vaultak dependencies. Given that vaultak is an external third-party package not in the project's dependencies, the sample cannot even be imported without it — meaning CI would fail if it were naively added to test_concepts.py. At minimum, unit tests with mocked vaultak calls should verify the filter logic (blocking on high scores, PII masking on output, terminate behavior).

✗ Design Approach

The main design issue is that the sample wires Vaultak into FUNCTION_INVOCATION, which in Semantic Kernel also wraps prompt functions. That makes this integration risk-score and potentially block kernel.invoke_prompt(...) turns before any plugin/tool call happens, which is broader than the PR describes and changes the behavior of the sample conversation itself.

Flagged Issues

  • KernelFunctionCanceledError does not exist in semantic_kernel.exceptions (or anywhere in the SK Python package). The only cancellation exception is OperationCancelledException (defined in python/semantic_kernel/exceptions/kernel_exceptions.py:55). Both the sample and the docs will fail with ImportError at import time.
  • vaultak_function_filter is attached at the FUNCTION_INVOCATION layer, which also covers prompt functions. Since chat() uses kernel.invoke_prompt(...) for every user turn, and invoke_prompt() creates a KernelFunctionFromPrompt that goes through self.invoke(...) (which always runs function-invocation filters), a high-risk-looking prompt can be blocked before any plugin function call or LM-selected tool call occurs. This is broader than the documented integration scope.

Suggestions

  • Gate the Vaultak FUNCTION_INVOCATION filter so it only applies to real plugin/tool functions (e.g., check context.function.plugin_name is not None), or move the blocking logic for tool use to the auto-function path, so the sample matches the stated 'plugin function call / LM tool selection' scope in the documentation.

Automated review by samueloladji-beep's agents

from semantic_kernel.connectors.ai import FunctionChoiceBehavior
from semantic_kernel.connectors.ai.open_ai import OpenAIChatCompletion, OpenAIChatPromptExecutionSettings
from semantic_kernel.contents import ChatHistory
from semantic_kernel.core_plugins import MathPlugin, TimePlugin
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

KernelFunctionCancelledError does not exist in semantic_kernel.exceptions. The module's __all__ exports only: KernelException, KernelFunctionAlreadyExistsError, KernelFunctionNotFoundError, KernelInvokeException, KernelPluginInvalidConfigurationError, KernelPluginNotFoundError, KernelServiceNotFoundError, OperationCancelledException. This import will raise ImportError at module load, making the sample completely non-functional.

Suggested change
from semantic_kernel.core_plugins import MathPlugin, TimePlugin
from semantic_kernel.exceptions import OperationCancelledException

Comment thread docs/VAULTAK_SECURITY.md
_api_key = os.environ.get("VAULTAK_API_KEY")
if not _api_key:
raise ValueError(
"VAULTAK_API_KEY environment variable is not set. "
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same KernelFunctionCanceledError import issue as the sample — this class does not exist. The docs quick-start will fail at import. Use OperationCancelledException (or a custom subclass).

Suggested change
"VAULTAK_API_KEY environment variable is not set. "
from semantic_kernel.exceptions import OperationCancelledException

kernel.add_service(OpenAIChatCompletion(service_id="chat"))
kernel.add_plugin(MathPlugin(), plugin_name="math")
kernel.add_plugin(TimePlugin(), plugin_name="time")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using FUNCTION_INVOCATION here makes Vaultak run on prompt functions too, not just plugin/tool calls. chat() drives every turn through kernel.invoke_prompt(...) (lines 123-129), which builds a prompt function and calls self.invoke(...) (kernel.py:248-255), always executing function-invocation filters. A risky user prompt can therefore be blocked before any plugin function call happens, which is broader than the docs describe.

- Replace KernelFunctionCancelledError (doesn't exist) with OperationCancelledException
- Add plugin_name is None guard to FunctionInvocationFilter so only real
  plugin/tool calls are risk-scored, not inline prompt invocations

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@samueloladji-beep
Copy link
Copy Markdown
Author

@dluc @craigomatic @glahaye — ready for review. This adds a Vaultak runtime security filter sample and guide using SK's FunctionInvocationFilter and AutoFunctionInvocationFilter.

@samueloladji-beep
Copy link
Copy Markdown
Author

Hey @moonbox3, all CI checks are passing — would appreciate a review when you get a chance. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation python Pull requests for the Python Semantic Kernel

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants