Sr. Content Developer at Microsoft, working remotely in PA, TechBash conference organizer, former Microsoft MVP, Husband, Dad and Geek.
159461 stories
·
33 followers

Build AI Agent-Driven Document Processing with Syncfusion Document SDK [Webinar Show Notes]

1 Share

Build AI Agent-Driven Document Processing with Syncfusion Document SDK [Webinar Show Notes]

AI can understand document requests, but turning those requests into reliable document operations requires the right tools. In this webinar, presenter Anantha Lakshmi Kannan demonstrated how Syncfusion® Document SDK AI Agent Tools help connect natural-language document requests with real document-processing workflows.

The session focused on how an AI document agent can interpret user prompts, select the appropriate Syncfusion document tools, process files, and generate output documents within an ASP.NET Core application.

If you missed the webinar or would like to review it, the recording has been uploaded to our YouTube channel and is embedded below.

What we covered

The webinar began with a common challenge in document automation: fixed workflows are easy to implement, but real business users often ask for dynamic tasks such as converting files, extracting data, redacting sensitive values, or generating final documents.

The session explained how AI can help understand natural-language intent, while Syncfusion Document SDK AI Agent Tools provide the trusted document-processing capabilities needed to execute the request. These Agent Tools expose document operations as AI-callable tools that an agent can invoke.

The webinar also covered how registered tools, storage-based document handling, system prompts, and streamed responses work together to create an end-to-end AI document workflow.

Demo highlights

The live demo used an AI-powered document-processing application with a document panel and chat interface. Users could view source documents, submit prompts, see tool activity in the chat, and download generated files from the Exports tab.

Markdown-to-Word conversion

The first demo showed how a Markdown file could be converted into a Word document using a natural-language request. The AI agent selected the appropriate Word tool and generated the output file automatically.

PDF redaction workflow

The second demo demonstrated a multistep PDF workflow in which the AI agent searched for specified text, applied redaction, and generated a redacted PDF.

Key takeaways

  • AI can understand document intent, but applications need reliable tools to execute document operations.
  • Syncfusion Document SDK AI Agent Tools expose document-processing operations as AI-callable tools.
  • Tool registration gives developers control over what the agent can do.
  • System prompts help guide agent behavior and keep workflows predictable.
  • The same pattern can be extended for conversion, redaction, extraction, security, and custom business operations.

Time stamps

[00:00] Introduction

[01:09] Webinar overview and agenda

[01:49] The challenge with traditional document automation

[03:01] Connecting AI with reliable document processing

[03:33] Live poll: Biggest document automation challenge

[04:30] Introducing Syncfusion Document SDK AI Agent Tools

[05:09] Demo overview: AI-powered document workflows

[06:26] Architecture: How the AI Agent workflow works

[07:39] Document storage: in-memory vs. storage mode

[08:45] Prerequisites and project setup

[09:50] Exploring the .NET project

[12:41] Front-end integration and user interaction

[14:10] File Management and chat controllers

[15:37] Session history and distributed cache

[16:31] Implementing document storage

[19:51] Building the AI Agent service

[21:18] Registering Document SDK AI Agent Tools

[23:39] Connecting tools to the AI Agent

[25:13] Defining the agent system prompt

[26:19] Creating the AI Agent

[27:10] Streaming agent responses to the UI

[28:18] Live demo begins

[29:19] Demo 1: Convert Markdown to Word

[30:14] Demo 2: Redact sensitive information from a PDF

[33:42] Multistep document processing workflow

[34:14] Live poll: Document agent use cases

[34:46] Key takeaways

Q&A

Q: Is the project to test available online?

A: Yes. You can access the online demo here. You can also explore our GitHub examples.

Q: Can you please describe the OpenAI interface you’ve used?

A: In this demo, OpenAI (LLM) is the brain, and Syncfusion AI Agent Tools are the hands that perform document operations.

The demo uses the Microsoft Agent Framework with an OpenAI-compatible model provider. Syncfusion AI Agent Tools expose AI-callable tools, and the LLM uses function/tool calling to invoke those document-processing operations as needed.

For more information about AI model providers and Syncfusion AI Agent Tools, refer to the following resources:

Related resources

Read the whole story
alvinashcraft
just a second ago
reply
Pennsylvania, USA
Share this story
Delete

How to implement Deep Data Security (DeepSec) in Oracle 26ai: complete step-by-step guide (part one)

1 Share

So you’ve been tasked with deploying a Generative AI, RAG (retrieval-augmented generation), or Agentic AI application. Have you thought about how to secure your most sensitive structured data – as well as your vectorized unstructured data?

The good news is, it’s relatively simple to implement complex security policies through the latest release ­of Oracle Database 26ai Deep Data Security (DeepSec).

In this guide, part one of my Oracle 26ai Deep Data Security (DeepSec) series, I’ll show you how – and will explain everything you need to know along the way.

Welcome to a security nightmare

Imagine this scenario. You’re the only Oracle DBA on a team of seasoned application developers, and you’ve just received a new mandate from the Chief of Police. Passed down from the new Mayor, the mandate involves implementing an AI-enabled chatbot that’ll access public and private information about crimes committed within the City.

The Chief wants to make it simpler for authorized personnel – such as district commanders, detectives, cops on the beat, criminologists, reporters, etc – to review data on crimes dating back to 2001. The Chief also knows that there is sensitive data within the current database that not everyone should see.

So, he needs you to guarantee one thing: only law enforcement personnel with proper permissions and clearances should see that information.

How do you achieve this level of privacy?

The basic ERD (entity relationship diagram) below shows how crime data is organized within the CPD schema. The callouts illustrate the complexity of the data security policies you’ll need to implement to ensure each user only sees the data they’re permitted to see.

An image showing Chicago Police Department (CPD) schema and security requirements.
Chicago Police Department (CPD) schema and security requirements.

Implementing data security requirements already looks a bit tricky, even with only five database objects. Now imagine how difficult it would be to build a comprehensive security strategy with only a series of database views that restrict viewing of specific rows within some tables for each user, based on which police district(s) they’re currently assigned to.

All while simultaneously hiding content of specific columns within other tables, of course.

Another crucial requirement is the ability to immediately reassign security privileges whenever a law enforcement officer (LEO) needs to urgently view data.

Perhaps they’ve been assigned to investigating crimes in one or more police district, or they’re restricted from viewing crime data that’s been marked as sensitive, secret, or confidential. They now need access to the data, and fast.

What about when it all goes wrong?

We’ve all watched enough police procedurals to know what happens when it goes wrong for a LEO. Let’s say, for example, they’re suddenly under investigation for bribery. The immediate result? They need to be blocked – urgently – from seeing internal affair reports on their potentially illicit activity.

What about a copper whose close friend has been accused of domestic violence? Perhaps the friend wants to find out what particulars their victim has reported? Worse still, maybe even find out in which shelter the victim now resides?

In all of these cases, the implications of poor security administration are potentially devasting. Fortunately, you’re reading this article, so the answer is simple. You must implement Oracle 26ai Deep Data Security (DeepSec).

Why data security is a complex web of limiting access

I first began investigating Oracle database security features a few years ago, during a stint as DBA for an Oracle Database 19c project. The DBA team I advised needed to implement a sure-fire method to limit users from viewing or changing data they shouldn’t.

The team had already attempted to implement Virtual Private Database (VPD), but with limited success. They’d rolled back their efforts after extreme frustration, and with good reason. Their complex data security requirements spanned dozens of tables, views, and materialized views across multiple schemas.

After some research, I helped them prototype a new security model using Real Application Security (RAS), VPD’s successor.

We also needed to tackle unexpected issues to implement RAS. We needed it to enforce row-level and column-level security within several robust and complex Application Express (APEX) applications. It didn’t help that, at the time, reliable documentation on how to integrate RAS with APEX was lacking.

Protect your data. Demonstrate compliance.

With Redgate, stay ahead of threats with real-time monitoring and alerts, protect sensitive data with automated discovery & masking, and demonstrate compliance with traceability across every environment.
Learn more

That wasn’t all…

There was one final wrinkle – my client’s user base, which also included several “power users”. These users typically used either SQL*Plus or SQL Developer to access their production database directly. They would then extract data in read-only mode for their own data warehouses or analytics. This meant we had to configure these power users as external RAS users.

Further, my client didn’t have the funding (or expertise) to set up an identity management system like Microsoft Active Directory (AD) or Oracle Identity Access Management (IAM). We therefore had to rebuild the security control mechanisms that were stored within their central database.

Last year I wrote about how RAS would be deployed in this scenario for the CPD schema within an Oracle 26ai database. I followed it up by explaining how RAS worked in concert with an AI chatbot deployed through Oracle APEX to limit end users from viewing outside their range of privileges.

That’s a good counterpoint to what I’ll be showing in this article, as well as future entries in the series. I suggest having a look at them before reading on.

How to implement Oracle DeepSec

The good news is, if you’re working with APEX 24.2 and Oracle Database 26ai, DeepSec is easy to implement. It’s also perfect for limiting access to data at both the row and column level with APEX applications.

Let’s focus on a typical workflow (below) to implement Oracle DeepSec. I’ll run through the whole process step-by-step, in detail.

An image showing a Oracle DeepSec implementation strategy.
Oracle DeepSec implementation strategy.

Prerequisites and assumptions before getting started

The rest of this article assumes the following prerequisite steps have already been completed:

  • A 26ai Autonomous Database (ADB) has already been created. It must be patched to version 23.26.2 to enable DeepSec features.

  • The CPD schema has already been created, populated with data, and all constraints and indexes have been applied. You can review the scripts to create and populate the CPD schema from this Github repository.

How to set Oracle DeepSec user limits (step 1)

First, create a new table (called it DEEPSEC_SECURED_USERS) within the CPD schema.

This is to hold specific security permissions and other information about each application user:

DROP TABLE IF EXISTS cpd.deepsec_secured_users PURGE;
CREATE TABLE IF NOT EXISTS cpd.deepsec_secured_users(
    rsu_username  VARCHAR2(25)  NOT NULL
   ,rsu_keytype   VARCHAR2(12)  NOT NULL
   ,rsu_keyvalue  VARCHAR2(12)  NOT NULL
   ,rsu_comment   VARCHAR2(128) 
);

ALTER TABLE cpd.deepsec_secured_users
  ADD CONSTRAINT deepsec_secured_users_pk
  PRIMARY KEY (rsu_username, rsu_keytype, rsu_keyvalue)
  USING INDEX (
    CREATE UNIQUE INDEX cpd.deepsec_secured_users_pk_idx
        ON cpd.deepsec_secured_users (rsu_username, rsu_keytype, rsu_keyvalue)
    );

You’ll need to populate this control table with data for each user, like what I did below:

A table showing end user permissions.
End user permissions. Note that only a few entries are shown here.
  • In this example, LSNELLING is the current Chief of Police. They have access to data from all CPD Districts, permission to view data in all columns, and permission to view rows at all four security levels.

  • Meanwhile, research assistant SNGUYEN only has access to data in a few districts – but can see report information at all four security levels.

  • User WJACKSON has extremely limited permissions as they’ve recently been reassigned to a new district due to ongoing Internal Affairs investigations.

  • Finally, NKURCHAWSKA is a student research assistant so has very limited privileges for just a few districts. They also can’t view any detailed report information.

Now, it’s on to creating Oracle DeepSec end users.

How to create Oracle DeepSec end users (step 2)

Since I’m working on an OCI-based 26ai autonomous database, for this example I’ll use the ADMIN account as my Oracle DeepSec administrator account. However, if you want to further isolate security administration to another user, you could also create a separate account – say, SECADM for my example.

On how to create Oracle DeepSec end users, you must firstly create DeepSec user accounts for each of them using the CREATE END USER command. Here’s how that works with my four example users:

CREATE END USER "LSNELLING"   IDENTIFIED BY "S3c-re_P5w0rd";
CREATE END USER "NKURCHAWSKA" IDENTIFIED BY "S3c-re_P5w0rd";
CREATE END USER "SNGUYEN"     IDENTIFIED BY "S3c-re_P5w0rd";
CREATE END USER "WJACKSON     IDENTIFIED BY "S3c-re_P5w0rd";

It’s important to note these are not regular database user accounts – they are specific to DeepSec security only. You use these DeepSec user accounts to connect to your database. It’s the same whether you’re using SQLcl, SQL*Plus, SQLDeveloper, or another database application written in APEX, Python, or Java.

How to create database roles in Oracle DeepSec (step 3)

To grant Oracle DeepSec access to specific tables within a schema, you need to create database roles that grant the required system privileges and different levels of access to database objects.

For my example, I created the following three database roles within the CPD schema:

-- Create a standard database role allowing CREATE SESSION access only 
CREATE ROLE adb_connect; 
GRANT CREATE SESSION TO adb_connect;

-- Create a standard database role for read-only access to fact tables 
CREATE ROLE cpd_readonly; 
GRANT adb_connect TO cpd_readonly; 
GRANT SELECT ON cpd.cpd_districts TO cpd_readonly; 
GRANT SELECT ON cpd.iucr_codes TO cpd_readonly; 
GRANT SELECT ON cpd.leo_resources TO cpd_readonly; 
GRANT SELECT ON cpd.ods_secured_users TO cpd_readonly;

-- Create a standard database role for full DML access to fact tables 
CREATE ROLE cpd_fulldml; 
GRANT adb_connect TO cpd_fulldml; 
GRANT cpd_readonly TO cpd_fulldml;
GRANT INSERT, UPDATE, DELETE ON cpd.cpd_districts TO cpd_fulldml; 
GRANT INSERT, UPDATE, DELETE ON cpd.iucr_codes TO cpd_fulldml; 
GRANT INSERT, UPDATE, DELETE ON cpd.leo_resources TO cpd_fulldml; 
GRANT INSERT, UPDATE, DELETE ON cpd.ods_secured_users TO cpd_fulldml;
  • Role ADB_CONNECT just grants CREATE SESSION permissions.

  • Role CPD_READONLY grants read-only access to the CPD schema’s reference tables.

  • And role CPD_FULLDML grants additional DML (data manipulation language) access to those same reference tables.

How to create data roles in Oracle DeepSec (step 4)

To enable Oracle DeepSec end user accounts to access database objects, you must create individual DeepSec data roles and grant them the required access.

For my example, I granted them access via the traditional database roles I just created:

DROP DATA ROLE cpd_dwro_role;
CREATE DATA ROLE cpd_dwro_role; 
GRANT cpd_readonly TO cpd_dwro_role;

DROP DATA ROLE cpd_full_role; 
CREATE DATA ROLE cpd_full_role;
GRANT cpd_fulldml TO cpd_full_role;

GRANT DATA ROLE cpd_dwro_role TO cpd_full_role;
GRANT DATA ROLE cpd_dwro_role TO nkurchawska, snguyen, wjackson;
GRANT DATA ROLE cpd_full_role TO lsnelling;
  • DeepSec data role CPD_DWRO_ROLE enables read-only access via database role CPD_READONLY.

  • DeepSec data role CPD_FULL_ROLE enables DML access via database role CPD_FULLDML. It also receives read access via a grant to CPD_DWRO_ROLE.

I then granted each DeepSec end user account the desired security permissions. End users NKURCHAWSKA, SNGUYEN, and WJACKSON receive just read-only capabilities but, since they’re the Chief of Police, end user LSNELLING receives full DML privileges.

How to create Oracle DeepSec data grants that limit data access (step 5)

It’s now time to create your very first Oracle DeepSec objects. For my example, I’ll be creating three dynamic roles that I’ll later use to assign privileges to DeepSec users as they log into the APEX application.

The CHICAGO_CRIMES table

In my example, the GRANT below enforces restrictions on rows within my table CHICAGO_CRIMES, based on which district(s) a user is allowed to access:

DROP DATA GRANT IF EXISTS cpd.limit_chicago_crimes_viewing_based_on_district;
CREATE OR REPLACE DATA GRANT cpd.limit_chicago_crimes_viewing_based_on_district
  AS 
    SELECT 
        ON cpd.chicago_crimes
     WHERE district IN (
         SELECT TO_NUMBER(rsu_keyvalue)
           FROM cpd.ods_secured_users 
          WHERE rsu_keytype = 'DISTRICT'
            AND rsu_username = ORA_END_USER_CONTEXT.username)
  TO cpd_dwro_role;

This is an excellent example of the powerful simplicity of Oracle DeepSec’s data security policies.

  • Since no specific column names are mentioned in that first SELECT statement, all columns in the CHICAGO_CRIMES table will be viewable by any DeepSec end user that’s been granted the CPD_DWRO_ROLE DeepSec security role.

  • After a database connection is established, the DeepSec object ORA_END_USER_CONTEXT ’s username attribute contains the end user name.

  • The WHERE clause limits the corresponding DeepSec end user granted the CPD_DWRO_ROLE to only viewing rows with a matching value for DISTRICT (found in the ODS_SECURED_USERS table for each end user.)

The CHICAGO_REPORTS table

In a similar fashion, I can build and apply a DATA GRANT for the CRIME_REPORTS table that limits access to rows with a matching value for the SENSITIVITY column, as found in ODS_SECURED_USERS for the connected DeepSec end user below:

DROP DATA GRANT IF EXISTS cpd.limit_crime_reports_viewing_based_on_sensitivity;
CREATE OR REPLACE DATA GRANT cpd.limit_crime_reports_viewing_based_on_sensitivity
  AS
    SELECT 
        ON cpd.crime_reports
     WHERE sensitivity IN (
         SELECT rsu_keyvalue
           FROM cpd.ods_secured_users 
          WHERE rsu_keytype = 'SENSITIVITY'
            AND rsu_username = ORA_END_USER_CONTEXT.username)
       AND crime_id IN (SELECT crime_id FROM cpd.chicago_crimes)
  TO cpd_dwro_role;

An important note on this data grant (the restriction linking CRIME_ID from CRIME_REPORTS to its parent table)

Since the prior data grant against CHICAGO_CRIMES will limit an end user to viewing rows in specific districts, that additional clause ensures only related rows in CRIME_REPORTS will be viewable based on the foreign key constraint on CRIME_ID.

The CHICAGO_VECTORS table

The last DATA GRANT enforces restrictions on the CRIME_VECTORS table in my example:

DROP DATA GRANT IF EXISTS cpd.limit_crime_vector_viewing;
CREATE OR REPLACE DATA GRANT cpd.limit_crime_vector_viewing
  AS 
    SELECT
        ON cpd.crime_vectors
     WHERE (
         SELECT rsu_keyvalue
           FROM cpd.ods_secured_users 
          WHERE rsu_keytype = 'VISIBILITY'
            AND rsu_username = ORA_END_USER_CONTEXT.username) = 'PII'
      AND doc_id IN (SELECT doc_id FROM cpd.crime_reports)
  TO cpd_dwro_role;

This limits access to rows within the table, based on whether the end user has a value of PII (personally-identifiying information) for the VISIBILITY column as found in ODS_SECURED_USERS.

Subscribe to the Simple Talk newsletter

Get selected articles, event information, podcasts and other industry content delivered straight to your inbox.
Subscribe

How to test Oracle DeepSec data grants (step 6)

You can ensure your security polices are configured properly by running some simple SQL queries against tables with Oracle DeepSec DATA GRANT‘s in place.

In my example, since the CPD_DWRO_ROLE role has already been granted to the Oracle DeepSec end users I’ve created, any restrictions and limitations I’ve enabled will take immediate effect.

How to prove the restrictions work as intended (test query #1)

The test query below, for my example, is relatively simple:

COL district    FORMAT 9999 HEADING "District"
COL sensitivity FORMAT A12 HEADING "Sensitivity"
COL crmcnt      FORMAT 99999 HEADING "Crime|Count"
COL doclen      FORMAT 999,999,999 HEADING "Document|Sizes"
COL emblen      FORMAT 999,999,999 HEADING "Embedding|Sizes"

TTITLE LEFT "Crime Vector Chunks + Embeddings Within District + Sensitivity"

SELECT
  CC.district
, CR.sensitivity
, COUNT(CC.crime_id) AS crmcnt
, SUM(LENGTH(CR.crime_document)) AS doclen
, SUM(LENGTH(CV.embeddings)) AS emblen
  FROM 
    cpd.chicago_crimes CC
   ,cpd.crime_reports CR
   ,cpd.crime_vectors CV
 WHERE CC.crime_id = CR.crime_id
   AND CV.doc_id = CR.doc_id
GROUP BY CC.district, CR.sensitivity
ORDER BY 1,2;

It joins together my CHICAGO_CRIMES, CRIME_REPORTS, and CRIME_VECTORS tables, retrieving information from all three to prove that the Oracle DeepSec limitations are working properly.

I can now use this query to demonstrate that the restrictions I put in place for my four end users actually work as they should (based on the DeepSec data grants I’ve built so far.)

Here’s what’s returned when I log into my database as one of my DeepSec END USERs – LSNELLING – and run this query:

An image showing what's returned when Jim logs into his database as one of his Oracle DeepSec end users.
The results for LSNELLING.

This end user can see information from every row in the database because they’re the owner of the data. They can see all districts, all sensitivity levels, and any information in the document embeddings.

When end user SNGUYEN connects and runs this same query, however, they see something quite different:

The results for SNGUYEN.
The results for SNGUYEN.

This is because they can only see information for the districts and sensitivity levels they’re permitted to see.

End user WJACKSON sees a completely different result as well:

What end user WJACKSON sees.
The results for WJACKSON.

WJACKSON can only see information for districts 8 and 10. This is because, if you remember, they’ve been transferred between the two districts due to an ongoing Internal Affairs investigation.

Note, also, that their sensitivity levels were adjusted to limit their viewing of reports deemed CONFIDENTIAL or SECRET.

Finally, when end user NKURCHAWSKA connects and runs this same query, the results are dramatically different than those of the other users:

The results for NKURCHAWSKA.

This user doesn’t have permission to access any data in the CRIME_VECTORS table, as defined in the LIMIT_CRIME_VECTOR_VIEWING DeepSec data grant. So, because my test query links data from all three tables, there are literally no results to return. A NULL set is returned as a result.

How to simulate AI chatbot search results (test query #2)

I’m not quite ready to deploy an AI chatbot yet – that’s for the next article in this series – so I built a simple query to leverage the existing embeddings within the CRIME_VECTORS table:

COL district    FORMAT 9999       HEADING "District" 
COL sensitivity FORMAT A12        HEADING "Sensitivity" 
COL doc_id      FORMAT 9999999    HEADING "Doc ID" 
COL chunk_id    FORMAT 999        HEADING "Chk|ID" 
COL distance    FORMAT 99.999999  HEADING "Vector|Distance”
COL doc_chunk   FORMAT A60        HEADING "Document Chunk" WRAP

TTITLE CENTER "VECTOR_DISTANCE Evaluations For Mention of CORRUPTION"

WITH embeddings_found AS (
 SELECT VECTOR_EMBEDDING(
   ADMIN.MINILML12V2 
   USING 'corruption' AS DATA) AS embedding 
   FROM DUAL) 
SELECT
  CC.district
, CR.sensitivity
, CV.doc_id 
, CV.chunk_id 
, VECTOR_DISTANCE(CV.embeddings, EF.embedding, COSINE) AS distance
, CV.doc_chunk 
  FROM cpd.chicago_crimes CC 
  JOIN cpd.crime_reports CR ON CR.crime_id = CC.crime_id 
  JOIN cpd.crime_vectors CV ON CV.doc_id = CR.doc_id 
  CROSS JOIN embeddings_found EF 
 ORDER BY VECTOR_DISTANCE(CV.embeddings, EF.embedding, COSINE)
 FETCH APPROXIMATE FIRST 3 ROWS ONLY WITH TARGET ACCURACY 95;
  • I’ve once again joined the CHICAGO_CRIMES, CRIME_REPORTS, and CRIME_VECTORS tables together, this time by using a CROSS JOIN (Cartesian) operation to retrieve from the CRIME_VECTORS.EMBEDDINGS column.

  • The query then uses the VECTOR_DISTANCE function to compare the cosine distance between the requested search token – in this case, what the AI LLM (large language model) determines is relevant to the concept of corruption.

  • Finally, the FETCH APPROXIMATE clause instructs the query to look for relevant results with a confidence level of 95%, returning only the top three results within what’s returned.

Don’t miss this useful trick

For my example, I need to grant permissions to the LLM I used to create the corresponding embeddings for the document chunks. This is to allow it to connect to my database and access those embeddings within CRIME_VECTORS.

To do this: GRANT SELECT ON MINING MODEL ADMIN.MINILML12V2 TO adb_connect;

What do the DeepSec users see?

One of my DeepSec example users, LSNELLING, sees these results:

The results for LSNELLING.
The results for LSNELLING.

Here, the top three document chunks returned are classified as SECRET, so the Chief of Police has a considerably wider view of corrupt activity within his jurisdiction (including some LEOs and even alderpersons!)

End user SNGUYEN, on the other hand, has a more limited view at a district level – receiving this set of results instead:

The results for SNGUYEN.
The results for SNGUYEN.

The vector distance scores are also higher here than of those for LSNELLING, indicating lower relevance to the context being searched.

Differing further are the results for WJACKSON, who has even narrower permissions for both district and sensitivity levels:

The results for WJACKSON.
The results for WJACKSON.

Lastly, what would user NKURCHAWSKA see? Well, since they don’t have permission to access CRIME_VECTORS, the embeddings are also inaccessible to the simulated chatbot interaction. And – just as I demonstrated for the first test query – no results are returned.

Next steps: implementing DeepSec in Oracle 26ai database applications (and how to do so)

If you’re thinking this has been a lot to absorb, you’re correct! The good news is, DeepSec is dramatically easier to implement than any of its Oracle Database predecessors. Better still, it’s more powerful.

In Part 2 of the series, I’ll explain how to implement Oracle DeepSec security constraints to limit access to sensitive information across a schema.

To do so, I’ll continue with my Chicago Police Department example schema in a sample database application. It’ll include how to deploy and use single sign-on (SSO) credentials to manage end user access.

Simple Talk is brought to you by Redgate Software

Take control of your databases with the trusted Database DevOps solutions provider. Automate with confidence, scale securely, and unlock growth through AI.
Discover how Redgate can help you

FAQs: How to implement Oracle DeepSec in Oracle Database 26ai

1. What is Oracle DeepSec in Oracle Database 26ai?

DeepSec (Deep Data Security) is a security framework in Oracle Database 26ai that lets administrators enforce row-level and column-level access controls across structured tables and vectorized data using DeepSec end users, data roles, and data grants.

2. How is DeepSec different from VPD or RAS?

DeepSec is designed to be significantly easier to configure than Virtual Private Database (VPD) or Real Application Security (RAS), especially for complex, multi-table security policies, while still supporting granular row- and column-level restrictions.

3. What are the main components needed to set up DeepSec?

A typical DeepSec setup includes a control table for user permissions, DeepSec end user accounts, standard database roles for object-level privileges, DeepSec data roles, and data grants that define row-filtering logic.

4. Can DeepSec restrict access to vector embeddings used by AI chatbots?

Yes. DeepSec data grants can limit which users or applications can query specific rows in a vector table (such as one holding document embeddings), which controls what an AI chatbot or LLM-powered search can retrieve on a user’s behalf.

5. What Oracle version and patch level are required for DeepSec?

This guide uses a 26ai Autonomous Database patched to release 23.26.2, along with Oracle APEX 24.2, as prerequisites for DeepSec features.

 

The post How to implement Deep Data Security (DeepSec) in Oracle 26ai: complete step-by-step guide (part one) appeared first on Simple Talk.

Read the whole story
alvinashcraft
just a second ago
reply
Pennsylvania, USA
Share this story
Delete

Microsoft removes Windows Management Instrumentation Command-line (WMIC) from Windows 11

1 Share
Microsoft has been on a drive to clean up Windows 11 by removing legacy features and components for some time now. The latest example of this is the company’s decision to remove Windows Management Instrumentation Command-line (WMIC) from the operating system. To the casual observer, this is something that has already been consigned to the history books as it was not included in a standard installation of Windows 11. However, the latest move sees Microsoft killing off the ability to add it as an optional Feature on Demand. The loss of Windows Management Instrumentation Command-line (WMIC) will not affect the… [Continue Reading]
Read the whole story
alvinashcraft
49 minutes ago
reply
Pennsylvania, USA
Share this story
Delete

How I Support Humans in the AI Era

1 Share
A remote engineering manager on why she didn't write a new AI policy for her team. Instead, she created space: for connection, for collaboration, and for discussion.
Read the whole story
alvinashcraft
49 minutes ago
reply
Pennsylvania, USA
Share this story
Delete

Skills Sprawl: When Too Much of a Good Thing Confuses Your AI Agent

1 Share

Introduction

In this post, we’re going to look at the problem of Skills Sprawl.

What happens if you have too many skills?

We’ll understand LLM decision fatigue and tool selection accuracy, inspect the mechanics of excluded vs inactive skills in Google Antigravity, and see how pruning your setup can make your agent smarter and save hundreds of thousands of tokens per session.

I have a special set of skills

Skills Context (It’s a Sort of Pun…)

Everyone knows that agent skills are awesome. If you don’t, then:

  1. Where have you been?
  2. You’re in for a treat!

In some of my previous posts I’ve talked about how skills act as on-demand power-ups for our agents. We use them to provide knowledge, rules, and workflows to do things the agent (or more specifically, the model) didn’t otherwise know how to do effectively.

You might have seen me compare this to how Neo loads his skills in the Matrix. “I know Kung Fu!”

This just-in-time knowledge provides a number of advantages to our agents:

  • They know how to do a thing well.
  • They don’t hallucinate the things they don’t know about.
  • They don’t have to experiment and course-correct; consequently, they’re more likely to succeed the first time, and they do it with a minimum number of tokens consumed.

In short: faster, cheaper, and more reliable.

Quick aside: when I say agent, I’m typically talking about your agentic partner in development crime, like Google Antigravity, Claude Code, or whatever. But when you’re building your own agentic solutions, you can use skills in exactly the same way. For example, check out my blog Automated GitHub Code Reviews Using Google Gemini, where I’ve built an agentic PR review solution that leverages skills.

Overview of Progressive Disclosure

Skills use a cool mechanism called progressive disclosure to load on-demand.

Let’s quickly recap this mechanism:

Progressive Disclosure

Level 1: Metadata (Frontmatter)

When your agent starts up, it reads the frontmatter  — and only the frontmatter  — of every installed skill in your global configuration and workspace.

By the way, if you don’t know where these skills should be placed, or you don’t know the difference between global and workspace locations, check out my earlier blog: Confused About Where to Put Your Agent Skills?

The frontmatter is simply the descriptive YAML at the top of each skill which contains the skill name, a description (what it does and when it should be used), and any additional useful metadata (such as what tools it might use, author, etc).

For example, this is from my maintaining-core-documentation skill:

name: maintaining-core-documentation
description: |
  Creates, maintains, and synchronises core project documentation 
  (README, TODO, DESIGN, Architecture, Testing, Deployment). 
  Use when the user needs to write, update, or structure project documentation 
  based on codebase changes, or whenever asked to perform documentation 
  reviews or updates.
metadata:
  author: Darren "Dazbo" Lester
  repository: https://github.com/derailed-dash/dazbo-agent-skills

Crucially, this frontmatter section is tiny. So even though the agent reads it up-front, it consumes very few tokens. Typically fewer than 100 tokens per skill.

The agent now has a mental model of all the skills that are available to it.

Level 2: Instructions Loading (On-Demand)

When the agent is asked to do a task that one of these skills might be useful for, the model selects the skill (based on the frontmatter), and then activates it. When this happens, the agent reads the SKILL.md body into context.

This will typically add several hundred, if not thousands of tokens.

Level 3: Resources and Code (As Needed)

Some skills may package additional resources, such as scripts, reference documents, or other assets. For example, my maintaining-core-documentation skill has a references subdirectory with several document template files.

These assets are only loaded as needed.

How This Helps

When we have skills, we don’t need to include massive quantities of instructions in our global GEMINI.md or AGENTS.md files. Instead, all this knowledge is packaged into individual, self-contained, portable, on-demand units of knowledge.

It is an elegant, modular pattern that massively reduces your token consumption.

But Can You Have Too Much of a Good Thing?

There’s no shortage of skills out there! You can use a public hub like skills.sh to find just about any skill you need. And, of course, you can create your own.

Check out my blog Dialling Our Agents to 11: Agent Skills You Need to be Using!, where I list some of my favourite skills.

The problem is… You end up collecting.

Collecting Skills

I recently asked Antigravity to tell me how many skills I have. (I have sarcasm dialled up…)

Well, Dazbo, according to my context window — which is currently groaning 
under the crushing weight of your digital hoard — you currently have a 
staggering 170 skills installed.

Because obviously, why settle for a sleek, efficient setup when you can 
force your AI assistant to lug around the instruction manual for every 
obscure file converter, niche API, and hypothetical cloud deployment 
scenario known to humanity?

Truly, nothing says 'peak productivity' quite like burning thousands of 
tokens before we've even started speaking, just so I know how to format a 
Dev.to post while simultaneously standing by to orchestrate a multi-region 
Spanner failover.

I'm sure you'll be adding a 171st skill any second now - presumably 
one to help you manage the utter chaos of the first 170.

Hilarious. 170. Maybe I have too many.

The irony here is that Antigravity’s last comment was spot on. I decided to build a skill to organise and optimise my skills!

What’s the Problem?

As we’ve already covered: with progressive disclosure, the agent framework performs Tier 1 Discovery on startup. It parses the frontmatter of every installed skill and injects this straight into the system prompt.

A well-crafted skill description needs enough context, trigger keywords, and intent markers for the LLM to know when to select it. (“Use when…”)

When I analysed my 170 skills, it turns out that my average skill frontmatter contained 103 tokens. Now let’s do some quick maths:

170 active skills × 100 tokens/description = 17,000 tokens

That means my agent is injecting 17,000 tokens of system prompt overhead on every single turn.

If I’m engaged in a typical 30-turn pair-programming session:

30 turns × 17,000 tokens = 510,000 tokens

That means I am burning an additional half a million tokens just to re-read the index of my skill library over and over again.

So what?

Let’s look at some of the potential issues this creates:

Issues of skills sprawl

  • Depending on your model choice, caching configuration, and AI subscription, there may be financial implications. But it’s likely to be small.
  • It will definitely eat into your token limits. Most models and plans have token limits and rate limits. Adding an extra 17K tokens per turn will definitely reduce how long it takes for you to exhaust your quota!
  • Most importantly, it’s confusing your model.

Confusion-Nation

Skills sprawl causes decision fatigue and skill selection accuracy degradation.

Skill selection confusion

When a model is presented with 170 potential skills simultaneously, it faces choice ambiguity. Many skills will naturally have overlapping domain descriptions. For example, my 170 skills had overlaps in each of these areas:

  • Content generation
  • API guides (particularly for Gemini APIs and SDKs)
  • Google products and services
  • Test-driven development (TDD) and code reviews

Does academic research back this up? Absolutely.

The Empirical Evidence: Shortlist Depth and Selection Accuracy

In a recent paper titled “How Many Tools Should an LLM Agent See? A Chance-Corrected Answer” (Repantis et al, May 2026), researchers evaluated LLM tool selection performance across 370 tools using the Berkeley Function Calling Leaderboard (BFCL) — the industry-standard benchmark for evaluating model tool-calling capabilities.

They concluded:

“Show too many tools and the model struggles to choose. Show too few and the correct tool may not appear.”

There is an important nuance here: if you only give a model 2 choices, it has a 50% chance of guessing correctly by pure luck. If you show it 50 choices, blind luck drops to 2%.

When the researchers corrected for random chance  — measuring genuine model comprehension rather than lucky guesses — the impact of list size was striking:

  • Presenting an LLM with a crowded shortlist of 50 tools resulted in 60.9% selection accuracy.
  • Scoping that shortlist down to ~7 focused tools boosted true accuracy to 76.8% (a 15.9% leap in decision precision).

Decision-making accuracy

Related benchmarks like MetaTool and ToolBench show the same results: as toolset sizes scale past 30–50 items without structured routing, error rates spike rapidly due to description collision and noise. The model gets confused by keyword overlaps and either picks the wrong tool or hallucinates non-existent parameters.

Okay, in this blog, I’m talking about skills, not tools. But the principle is the same. Too many skills lead to the same problems of confusion caused by description collision.

We want:

  • Our agent to pick the right skills with a high degree of accuracy.
  • To avoid burning unnecessary tokens.

I need a way to optimise my installed skills!

Why Do I Have So Many Skills?

Before I start pruning my skills, I need to understand why I have so many.

I went back and reviewed my Git history to trace how I got here. Here’s what I discovered:

  1. Google Cloud & AI knowledge: Over 120 skills pulled from official Google repositories, including google/skills, google/agents-cli, google-gemini/gemini-skills, and GoogleCloudPlatform/vertex-ai-creative-studio. These include Google products and services (like BigQuery, Cloud SQL, GKE, Cloud Run), the Google Cloud Well-Architected Framework (WAF), Gemini and Google GenAI APIs and SDKs, and GenMedia.
  2. Dazbo Agent Skills: Custom skills I wrote for derailed-dash/dazbo-agent-skills for documentation, blogging, security, installing automated PR code reviews, skill organisation, and deployment.
  3. Core Software Engineering & Best Practices: 25 skills adopted from Addy Osmani’s addyosmani/agent-skills repository covering TDD, code review, debugging, interface design, context engineering, and software delivery workflows.
  4. Research, Strategy & Technical Writing: 5 specialised skills installed from Shubham Saboo’s shubhamsaboo/awesome-llm-apps repository (deep-research, fact-checker, strategy-advisor, technical-writer, content-creator).
  5. Specialised & Community Skills: Niche skills sourced from specific community repositories, including wshobson/agents (documentation-and-adrs, interview-me), coreyhaines31/marketingskills (seo-audit), remotion-dev/skills (remotion-best-practices), and vercel-labs/skills (find-skills).

Here is the complete breakdown of the 170 skills I had installed, grouped by category and origin repository:

Group / Category Count Source Repository / Origin Link Summary of Included Skills
Google Cloud Core Services & WAF 82 google/skills GCP product & infrastructure guides (BigQuery, Cloud SQL, AlloyDB, GKE, Cloud Run, Firebase), Well-Architected Framework (WAF) pillars, networking, and developer APIs (Google Ads, Analytics, Mobile Ads).
Addy Osmani Engineering Workflows 25 addyosmani/agent-skills SDLC & software engineering workflow heuristics covering TDD, code review, debugging, context engineering, spec-driven development, and interface design (orchestrated via using-agent-skills).
Google Agent Platform & ADK CLI 20 google/agents-cli Agent Development Kit (ADK) CLI lifecycle tools (scaffolding, testing, evaluation, deployment, publishing) and server-managed Agent Platform resource handlers.
Specialized & Community Skills 14 Various Community Sources Niche tools and community extensions including Dev.to formatting, Playwright browser testing, Remotion React video, SEO auditing, Python dependency management, and skill discovery (find-skills).
Gemini API & GenAI SDKs 10 google-gemini/gemini-skills Technical integration guides for the Gemini API (google-genai SDK), multimodal streaming, Live API, NotebookLM auth, and server-managed interactions.
Google GenMedia & Creative Studio 8 vertex-ai-creative-studio Specialized role personas for multimedia production (audio engineering, image generation, video editing, voice direction, script producing, story generation).
Dazbo Custom Agent Skills 7 derailed-dash/dazbo-agent-skills Personal workflow automation for documentation maintenance, blog writing (dazbo-content), secrets management (git-crypt), UTM link tagging, PR review actions, skill organisation, and deployment.
Awesome LLM Apps (Research & Content) 5 shubhamsaboo/awesome-llm-apps Autonomous research, fact-checking, strategy advisory, and technical documentation generation workflows.
TOTAL 170

So you can see how easy it is for your skills base to get out of hand! Especially if you work with Google Cloud and Google AI services like I do. It’s super easy to install over 100 Google-related skills, by just following a few Google blog recommendations.

Next Question: Do I Need Them All?

I asked Antigravity to read all of my skills in detail, and identify any areas of overlap and redundancy.

There was a LOT of redundancy! We uncovered seven major categories of overlap, duplication, and inefficiency:

  1. Exact Byte-for-Byte File & Naming Duplicates: In google/skills, the skill directory gemini-agents-api declared name: gemini-managed-agents-api in its frontmatter. This directory vs. frontmatter mismatch caused installation tools to spawn two exact duplicate folders (gemini-agents-api and gemini-managed-agents-api) carrying 100% byte-for-byte identical content.
  2. Deprecated SDKs vs. Modern APIs: Older skills still provided code snippets using the deprecated google-generativeai package and obsolete model strings, directly contradicting modern google-genai SDK standards and confusing the agent during code generation.
  3. API Guide Overlaps & Fragmentation Across Repositories: The gemini-api skill in google/skills (which exists as an enterprise Agent Platform guide) collided directly with gemini-api-dev in google-gemini/gemini-skills. Installing across multiple Google repositories resulted in competing guides for the same underlying APIs (gemini-api, gemini-api-dev, gemini-agents-api, gemini-interactions-api, and gemini-live-api-dev).
  4. Irrelevant Domain Bundles (The Monolithic Repo Problem): Pulling down the monolithic google/skills repository imported mobile advertising suites (Android/iOS banner ads, Unity SDKs) that had zero relevance to cloud backend architecture and agent development.
  5. Hierarchical Sub-Skill Redundancies (The Meta-Skill Tax): 25 individual SDLC skills from addyosmani/agent-skills (such as test-driven-development and code-review-and-quality) were loaded into system prompt context at startup, despite being child sub-skills already orchestrated on-demand by using-agent-skills. Similarly, 20 sub-skills from google/agents-cli were loaded continuously rather than routed via google-agents-cli-workflow.
  6. Tooling & MCP Surface Overlaps: Standalone tools like the adk-docs-mcp server were redundant because google-developer-knowledge already indexes ADK documentation (adk.dev).
  7. Capability & Persona Redundancies: documentation-and-adrs (addyosmani/agent-skills) was a duplicate of architecture-decision-records (wshobson/agents), while generic content-creator (shubhamsaboo/awesome-llm-apps) collided with my custom dazbo-content persona.

What Else Did I Discover?

Beyond the sheer volume of redundant skills, I made another cool discovery: many skill collections come with a “parent” Meta-Skill.

When you install a large collection of skills — such as Addy Osmani’s engineering skills (addyosmani/agent-skills), or Google's 20 Agent Platform skills (google/agents-cli) — your instinct is to leave all 20 to 25 skills enabled in your workspace. I mean... Why wouldn't you?

However, these skill suites are designed to be hierarchical:

  • addyosmani/agent-skills: Orchestrated by the using-agent-skills meta-skill.
  • Google ADK & Agent Platform: Orchestrated by the google-agents-cli-workflow meta-skill.
  • GCP Data Pipelines: Orchestrated by the gcp-data-pipelines meta-skill.

In each case, the parent meta-skill is supposed to work as a sort of skills index or decision tree. When a specific task comes in — such as writing unit tests or running a security audit — the parent meta-skill directs the agent to fetch and read only the specific child sub-skill from disk on demand.

Parent meta-skill routing

Conclusion? We don’t need to load the frontmatter of all the child skills. We only need the parent skill! In the examples above, I can easily replace nearly 50 skills with just 3 orchestration skills!

So now I could implement a solution to organise my skills. The primary objectives:

  • Remove skills that are truly redundant.
  • Prevent Level 1 skills loading (i.e. reading frontmatter into context) for skills that have parent meta-skills. For these, only pre-load the parent meta-skills.

Clarifying Skill States

To design a lean agent workspace, we must be crystal clear on the three distinct states a skill can occupy throughout its lifecycle. They can be:

  • Installed and inactive (discoverable).
  • Installed and excluded.
  • Activated.

Let’s define these in more detail:

  1. Installed and inactive (discoverable): These skills are present on disk and discoverable by our agent. When the agent (e.g. Antigravity) starts, their frontmatter is automatically read into context.
  2. Installed and excluded: These skills reside in your disk library but are excluded from automatic Level 1 loading. For these, the agent does not automatically read their frontmatter and is therefore not directly aware of them during your conversation with it. But because they are present on disk and available to the agent, they can still be explicitly activated.
  3. Activated: This is the runtime state when a skill’s full SKILL.md body has been loaded into the current turn context, i.e. Level 2 loading (and Level 3, where supporting files are present and appropriate).

Crucially, both installed and inactive and installed and excluded skills can transition into this Activated state.

Skill states

Excluding Skills

So now we know that a good optimisation strategy is to use exclusion to prevent a bunch of skills being loaded at startup into the “Installed and inactive” state.

But how can we do this?

In Google Antigravity, global skill exclusions are managed via ~/.gemini/config/skills.json (or .agents/skills.json for workspace-level skills).

The native exclude array accepts skill folder names. For example:

{
  "exclude": [
    "alloydb-basics",
    "cloud-spanner-migrations",
    "firebase-basics"
  ]
}

Any skill listed in the exclude array is completely skipped during Tier 1 discovery. Its frontmatter is therefore not injected into the system prompt, saving tokens instantly.

So this is easy!

But here’s a cool trick. You can easily “un-exclude” a skill by prefixing its name with // inside the quotes. This is useful because it allows us to re-enable up-front skill loading, without having to check our disk to find the skill and its name.

So my approach is to always have all my available skills in the exclude list, but to comment-out the ones that need to be discovered automatically.

Note: I have the // inside the quotes. Why? Because this is not valid JSON:

{
  "exclude": [
    //"alloydb-basics",
    //"find-skills",
    "firebase-basics"
  ]
}

But this is:

{
  "exclude": [
    "//alloydb-basics",
    "//find-skills",
    "firebase-basics"
  ]
}

And because the exclude list uses exact string matching, you can use this // trick to enable/exclude skills on the fly, without having to remove the skill from the exclude list entirely.

In the example above:

  • alloydb-basics and find-skills are not excluded, so they are auto-discovered on startup and their frontmatter is loaded into context.
  • firebase-basics is excluded, so it is not auto-discovered on startup and its frontmatter is not loaded into context.

Now we’ve got everything we need to implement a repeatable mechanism to organise and clean up our skills.

Irony and Guitars: I Made a Skill!

Because: when you’ve got too many skills, you definitely need one more. (In this way, skills are a lot like guitars, or cats.)

Skills are like guitars and cats

Anyway, based on what I learned, I created a skill that:

  1. Identifies duplicative skills and recommends complete removal of those that are redundant.
  2. Identifies which skills are orchestrated by a parent meta-skill and excludes the child skills from automatic discovery.
  3. Identifies skills which look particularly niche or rarely used, and recommends excluding these also. They can always be included later, or even activated by explicitly asking the agent to do so.

Let’s see how it performs! After installing my skill, I said to Antigravity:

“Optimise my skills please”

Outcomes of Optimising

My skill ran and presented this proposal summary table:

Metric Baseline (Unoptimised) Proposed (Optimised) Delta / Savings
Installed Skills Directories 170 165 -5 (-2.9%)
Installed & Discoverable Skills 170 49 -121 (-71.2%)
Installed & Excluded Skills 0 116 +116
Prompt Token Overhead ~17,000 tokens ~3,350 tokens -13,650 tokens (-80.3%)

It goes on to say:

Upon your confirmation, I will execute the following steps:

1. **Retire Redundant Skills**: Delete the 5 redundant skill directories
   (`gemini-managed-agents-api`, `liveapi-service`, `documentation-and-adrs`, 
   `gemini-api-dev`, `gemini-live-api-dev`) from `~/.gemini/config/skills/`.
2. **Generate Optimised `skills.json`**: Write the full-inventory 
   `~/.gemini/config/skills.json` with 49 active skills (`//` prefix) and 
   116 excluded skills.
3. **Verify Context Footprint**: Re-audit the active skill prompt token 
   overhead to confirm successful reduction to ~3,350 tokens.

---
> [!IMPORTANT]
> **Mandatory Guardrail Confirmation**: In accordance with 
  `organise-agent-skills` guardrails, please confirm if you would like me 
  to proceed with deleting the 5 redundant skill directories and creating 
  the optimised `~/.gemini/config/skills.json`.

By trimming back to a core of 49 active skills and delegating the rest to meta-skills and on-demand rules:

  • We slashed system prompt overhead by approximately 13,650 tokens; that’s an 80.3% reduction.
  • We saved over 400,000 tokens per pair-programming session.
  • Agent response latencies dropped noticeably.
  • Tool selection precision increased because the agent was no longer fighting distractor noise from over 100 overlapping skill descriptions. Instead of having a mild existential crisis every turn trying to choose between five different Gemini SDK guides, the agent simply picks the right tool and gets on with the job.

Optimisation results

Summary & Conclusion

Agent skills are awesome. They’re so easy to find, install and use. But when we allow skills to sprawl unchecked, we start confusing our agents. This impacts accuracy, reliability, performance, and cost.

So increasingly, we need a way to manage and optimise our skills. For this, I’ve done some work so you don’t have to!

Feel free to download my optimisation skill off-the-shelf:

# Install all the Dazbo Agent Skills
npx skills add https://github.com/derailed-dash/dazbo-agent-skills

# Install just the `Organise Agent Skills` skill
npx skills add https://github.com/derailed-dash/dazbo-agent-skills --skill organise-agent-skills

Or if you have the Vercel find-skills skill installed, you can just ask your agent:

“Install dazbo-agent-skills for me.”

So, that’s it, folks. Go forth and optimise. If you find this skill useful, please give the repo a star.

Have you experienced Skills Sprawl in your agentic environment? How many skills are currently active in your setup? Let me know in the comments below!

Before You Go

  • Please share 📢 this with anyone that you think will be interested. It might help them, and it really helps me!
  • Please give me loads of reactions / hearts! 💖
  • Please leave a comment 💬. Interaction is good!
  • Add a star ⭐ on my repos!
  • Follow 👉 and subscribe 🔔, so you don’t miss my content.

References and Useful Links

Standards, Hubs & Agent Platforms

Related Dazbo Articles & Repositories

Key Agent Skills Repositories

Academic Research & Benchmarks

Read the whole story
alvinashcraft
49 minutes ago
reply
Pennsylvania, USA
Share this story
Delete

Building Enterprise Active Directory, LDAP & Dynamic RBAC in Go & Flutter with Google Antigravity

1 Share

Building Enterprise Active Directory, LDAP & Dynamic RBAC in Go & Flutter with Google Antigravity

When building a lightweight container orchestrator like Gubernator (gbnt) — designed to strike the perfect balance between the simplicity of Docker Swarm and the flexibility of Nomad under a Roman Empire theme — a critical milestone inevitably emerges: Enterprise Security and Access Control.

While a default admin credential works well for local dev environments, moving into enterprise production with multi-disciplinary engineering teams demands:

  1. Corporate Single Sign-On (SSO) with Microsoft Active Directory and OpenLDAP.
  2. Role-Based Access Control (RBAC) to clearly segregate who can deploy stacks, restart containers, or audit telemetries in read-only mode.
  3. Dynamic Group Mapping from corporate security groups (memberOf) to orchestrator roles.
  4. Emergency Break-Glass Access (Local Administrator) in case network directory controllers are unreachable.

In this article, we explore the complete architecture of the enterprise security engine introduced in Gubernator v2.20.0, and how we leveraged Google Antigravity (AGY) as an autonomous AI pair programmer to design, implement, test, and verify this Full-Stack feature (Go + Flutter Web) across a live 3-node cluster.

The Security Architecture

We designed a decoupled, asymmetric architecture connecting identity providers, REST API middleware, and the Flutter Web UI:

 ┌────────────────────────────────────────────────────────┐
 │                   GUBERNATOR WEB UI                    │
 │   - Modern Login Screen with Domain / AD Selector      │
 │   - Header Role Badge: Admin |  Ops |  Read-Only.      │
 └──────────────────────────┬─────────────────────────────┘
                            │ (REST /api/auth/login)
                            ▼
 ┌────────────────────────────────────────────────────────┐
 │             GUBERNATOR CORE AUTH ENGINE (Go)           │
 │  - Local Emergency Admin (admin / admin fallback)      │
 │  - Multi-Server Active Directory / OpenLDAP Dialers    │
 │  - LDAPS (Port 636) & StartTLS (Port 389) Handshake    │
 │  - Dynamic Group DN -> RBAC Role Resolution            │
 │  - Cryptographic HMAC-SHA256 JWT Token Signing         │
 └─────────────┬────────────────────────────┬─────────────┘
               │                            │
               ▼                            ▼
 ┌───────────────────────────┐ ┌──────────────────────────┐
 │  Primary Active Directory │ │ Secondary LDAP Server    │
 │   dc1.corporate.local     │ │   dc2.dr-site.local      │
 └───────────────────────────┘ └──────────────────────────┘

Role-Based Access Control (RBAC) Matrix

We established three distinct operational tiers:

Operational Capability admin operator readonly
Overview, Metrics & SRE Telemetry ✅ Full ✅ Full ✅ Full
Deploy Stacks (docker-compose.yml) ✅ Full ✅ Full ❌ Restricted
Redeploy & Duplicate Stacks ✅ Full ✅ Full ❌ Restricted
Delete Stacks ✅ Full ❌ Restricted ❌ Restricted
Task Lifecycle (Start / Stop / Restart) ✅ Full ✅ Full ❌ Restricted
Container & Node Terminal Shell ✅ Full ✅ Full ❌ Restricted
Node Fleet Management (Drain / Activate / Leave) ✅ Full ❌ Restricted ❌ Restricted
Caddy TLS Certificates & Ingress Routes ✅ Full ❌ Restricted ❌ Restricted
Active Directory & LDAP Directory Settings ✅ Full ❌ Restricted ❌ Restricted
Grafana, Jaeger & Weave Scope Dashboards ✅ Full ✅ Full ✅ Full

💻 The Go Backend Engine (internal/auth/)

For LDAP/Active Directory interactions, we used github.com/go-ldap/ldap/v3, and for session management github.com/golang-jwt/jwt/v5.

1. Two-Phase Bind & Credential Verification

Authentication follows a secure two-phase pattern:

  1. Connect and perform a Service Account Bind (BindDN / BindPassword) to query the directory.
  2. Search for the user object using a configurable LDAP filter (defaulting to (&(objectClass=user)(sAMAccountName=%s))).
  3. Open a secondary connection and perform a Direct User Bind with the user-submitted password against the domain controller.
func AuthenticateLDAP(cfg db.LDAPConfig, username, password string) (*AuthResult, error) {
    conn, err := ConnectLDAP(cfg)
    if err != nil {
        return nil, err
    }
    defer conn.Close()

    // 1. Initial service account bind
    if cfg.BindDN != "" && cfg.BindPassword != "" {
        if err := conn.Bind(cfg.BindDN, cfg.BindPassword); err != nil {
            return nil, fmt.Errorf("service account bind failed: %w", err)
        }
    }

    // 2. Search for the user
    filter := fmt.Sprintf(cfg.UserFilter, ldap.EscapeFilter(username))
    searchReq := ldap.NewSearchRequest(
        cfg.BaseDN,
        ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
        filter,
        []string{"dn", "displayName", "mail", "memberOf"},
        nil,
    )
    sr, err := conn.Search(searchReq)
    if err != nil || len(sr.Entries) == 0 {
        return nil, errors.New("user not found in directory")
    }

    userEntry := sr.Entries[0]

    // 3. Direct user bind to verify password
    userConn, err := ConnectLDAP(cfg)
    if err != nil {
        return nil, err
    }
    defer userConn.Close()

    if err := userConn.Bind(userEntry.DN, password); err != nil {
        return nil, errors.New("invalid credentials")
    }

    // 4. Map groups to RBAC role
    groups := userEntry.GetAttributeValues("memberOf")
    role := ResolveRole(cfg, groups)

    return &AuthResult{
        UserDN:      userEntry.DN,
        Username:    username,
        DisplayName: userEntry.GetAttributeValue("displayName"),
        Email:       userEntry.GetAttributeValue("mail"),
        Groups:      groups,
        Role:        role,
    }, nil
}

2. Dynamic Group-to-Role Mapping

Gubernator inspects the user's memberOf group list and matches them against the configured group DNs:

func ResolveRole(cfg db.LDAPConfig, userGroups []string) Role {
    matchesGroup := func(targetGroup string) bool {
        if targetGroup == "" { return false }
        target := strings.ToLower(strings.TrimSpace(targetGroup))
        for _, g := range userGroups {
            if strings.ToLower(strings.TrimSpace(g)) == target {
                return true
            }
        }
        return false
    }

    if matchesGroup(cfg.AdminGroupDN) { return RoleAdmin }
    if matchesGroup(cfg.OperatorGroupDN) { return RoleOperator }
    if matchesGroup(cfg.ReadOnlyGroupDN) { return RoleReadOnly }

    return NormalizeRole(cfg.DefaultRole)
}

The Flutter Web UI Experience

Gubernator's Web Dashboard is built with Flutter Web and Material Design 3, compiled and embedded directly into the Go binary (go:embed).

1. Modern Login Screen with Domain Selector

Operators can select their target authentication provider (Corporate Active Directory, DR Site LDAP, or Local Administrator):

Login Screen

2. Active Directory Management & Diagnostics

In the new Seguridad & AD tab, cluster administrators can configure directory servers, TLS certificates, and run a live "Test Connection" diagnostic tool:

Security & AD Management

3. Real-Time Role Badges & Contextual Guards

The dashboard header displays the active user and their assigned role (ADMIN, ⚡ OPERATOR, READ-ONLY). Mutating actions (e.g., Delete Stack, Drain Node, Shell) are automatically disabled for read-only audit accounts.

How Google Antigravity Accelerated Development

We utilized Google Antigravity (AGY) as an autonomous AI pair programmer to build this feature end-to-end. AGY accelerated the development cycle through several key workflows:

  1. Architectural Planning:
    Before writing code, Antigravity produced a comprehensive implementation plan (implementation_plan.md) outlining the GORM schema changes (LDAPConfig), RBAC authorization matrix, and API routes.

  2. Synchronized Full-Stack Implementation:
    In a single coordinated session, Antigravity:

    • Built the Go internal/auth/ engine with LDAP dialers, JWT session handlers, and Gin middlewares.
    • Applied SQLite database auto-migrations.
    • Implemented the Flutter Web UI (login_screen.dart, security_page.dart, and state models).
    • Updated existing views (legions_page.dart, tasks_page.dart, centurions_page.dart) with RBAC permission guards.
  3. Live Cluster Testing & Verification:
    Using automated commands across a 3-node multipass cluster (gbnt-manager, gbnt-worker1, gbnt-worker2), Antigravity:

    • Deployed and hot-restarted the ARM64 binaries.
    • Tested REST endpoints via curl (valid login, invalid login, LDAP connection tests, configuration lifecycle).
    • Executed Go unit tests (go test ./internal/auth/...) with 100% pass rates.
  4. Automated Documentation & Release:

    • Generated high-fidelity visual UI showcases.
    • Authored complete documentation in docs/auth-rbac.md and validated MkDocs builds in strict mode.
    • Bumped the version to v2.20.0, created git release tags, and triggered GitHub Pages publishing.

Conclusion & Open Source

Adding Active Directory SSO and RBAC allows teams to deploy Gubernator in enterprise production environments that require enterprise security compliance without the operational overhead of Kubernetes.

Check out Gubernator and try it out:

What do you think about this hybrid approach to container orchestration? Let us know your thoughts and suggestions in the comments!

Read the whole story
alvinashcraft
49 minutes ago
reply
Pennsylvania, USA
Share this story
Delete
Next Page of Stories