This is an automated email from the ASF dual-hosted git repository.

hsluoyz pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/casbin-gateway.git

commit 0d7932c3f0529df0da1250ad69cc12b2c8cdec25
Author: Yang Luo <[email protected]>
AuthorDate: Fri Sep 4 18:23:28 2026 +0800

    fix(agents): don't count an agent's own scratch state as an install
---
 agent/fingerprint.go                |  8 ++++++--
 agent/fingerprint_load.go           |  3 +++
 agent/fingerprints/copilot-cli.json |  1 +
 agent/scan_common.go                | 31 +++++++++++++++++++++++++------
 4 files changed, 35 insertions(+), 8 deletions(-)

diff --git a/agent/fingerprint.go b/agent/fingerprint.go
index 0ae67e1..6373872 100644
--- a/agent/fingerprint.go
+++ b/agent/fingerprint.go
@@ -70,6 +70,10 @@ type Fingerprint struct {
        // StateVersionGlob matches JSONL files under the state directory whose
        // records carry the version of the agent that wrote them. It is the 
only
        // version an installation found by its configuration alone can report.
-       StateVersionGlob string              `json:"stateVersionGlob,omitempty"`
-       LocalServer      *localserver.Server `json:"localServer,omitempty"`
+       StateVersionGlob string `json:"stateVersionGlob,omitempty"`
+       // StateIgnore names the entries an agent writes on its own, without 
being
+       // installed here: what an app that embeds the agent leaves behind. A 
state
+       // directory holding nothing else is not evidence of an installation.
+       StateIgnore []string            `json:"stateIgnore,omitempty"`
+       LocalServer *localserver.Server `json:"localServer,omitempty"`
 }
diff --git a/agent/fingerprint_load.go b/agent/fingerprint_load.go
index 5d971ae..905b6c1 100644
--- a/agent/fingerprint_load.go
+++ b/agent/fingerprint_load.go
@@ -111,6 +111,9 @@ func validateFingerprint(f Fingerprint, name string) error {
        if f.StateVersionGlob != "" && f.StateDir == "" {
                return errors.New("stateVersionGlob has no stateDir to resolve 
against")
        }
+       if len(f.StateIgnore) > 0 && f.StateDir == "" {
+               return errors.New("stateIgnore has no stateDir to resolve 
against")
+       }
 
        if err := validateLocalServer(f.LocalServer); err != nil {
                return err
diff --git a/agent/fingerprints/copilot-cli.json 
b/agent/fingerprints/copilot-cli.json
index 82239dc..5ee11b2 100644
--- a/agent/fingerprints/copilot-cli.json
+++ b/agent/fingerprints/copilot-cli.json
@@ -4,5 +4,6 @@
   "installUrl": 
"https://docs.github.com/en/copilot/concepts/agents/about-copilot-cli";,
   "execName": "copilot",
   "stateDir": "copilot",
+  "stateIgnore": ["config.json", "logs"],
   "npmPackage": "@github/copilot"
 }
diff --git a/agent/scan_common.go b/agent/scan_common.go
index 58f3d20..7a93a20 100644
--- a/agent/scan_common.go
+++ b/agent/scan_common.go
@@ -189,7 +189,7 @@ func scanStateDirs(fingerprint *Fingerprint, homes 
[]homeDir, found []Installati
        installations := []Installation{}
        for _, home := range homes {
                path := filepath.Join(home.path, "."+fingerprint.StateDir)
-               if !hasEntries(path) {
+               if !hasSetupEntries(path, fingerprint.StateIgnore) {
                        continue
                }
                installations = append(installations, Installation{
@@ -203,17 +203,36 @@ func scanStateDirs(fingerprint *Fingerprint, homes 
[]homeDir, found []Installati
        return installations
 }
 
-// hasEntries reports a directory that holds something. An empty one is what an
-// uninstall leaves behind, and is not evidence that the agent was ever set up.
-func hasEntries(path string) bool {
+// hasSetupEntries reports a directory that holds something the agent only
+// writes once it is set up here. An empty one is what an uninstall leaves
+// behind, and one holding nothing but ignored entries is what an app that
+// embeds the agent leaves behind; neither is evidence of an installation.
+func hasSetupEntries(path string, ignore []string) bool {
        dir, err := os.Open(path)
        if err != nil {
                return false
        }
        defer dir.Close()
 
-       names, err := dir.Readdirnames(1)
-       return err == nil && len(names) > 0
+       names, err := dir.Readdirnames(-1)
+       if err != nil {
+               return false
+       }
+       for _, name := range names {
+               if !matchesAny(name, ignore) {
+                       return true
+               }
+       }
+       return false
+}
+
+func matchesAny(name string, candidates []string) bool {
+       for _, candidate := range candidates {
+               if strings.EqualFold(name, candidate) {
+                       return true
+               }
+       }
+       return false
 }
 
 // dedupeInstallations returns unique installations ordered by owner and path.


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to