From 1f3999d90d1e6e0b03a4a48b6a69467b6528a97a Mon Sep 17 00:00:00 2001 From: servicememeai Date: Fri, 23 Oct 2026 19:07:44 +0900 Subject: [PATCH 1/3] fix(acl): evaluate directory and file kinds correctly in native batch --- common/cf-acl.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/common/cf-acl.c b/common/cf-acl.c index 9f4f8215..2e5fb795 100644 --- a/common/cf-acl.c +++ b/common/cf-acl.c @@ -1,6 +1,7 @@ /* CloudFile V2 native permission seam; no library enrollment or class. */ #include "common.h" #include +#include #include #include "log.h" #include "seafile-session.h" @@ -95,16 +96,21 @@ filter_chunk (const char *repo, const char *dir, const char *user, for (GList *p=begin; p && count > 0; p=p->next, --count) { GObject *item=p->data; char *name=NULL; - g_object_get(item,"obj_name",&name,NULL); + int mode=0; + g_object_get(item,"obj_name",&name,"mode",&mode,NULL); if (!name || !*name || strchr(name,'/') || - !strcmp(name,".") || !strcmp(name,"..")) { + !strcmp(name,".") || !strcmp(name,"..") || + (!S_ISDIR(mode) && !S_ISREG(mode))) { g_free(name); goto done; } char *path=g_build_filename(dir,name,NULL); g_free(name); + /* File rights follow the containing directory; a directory entry + * follows its own path. Both use Hub's same Authority rule snapshot. */ + const char *kind=S_ISDIR(mode) ? "dir" : "file"; json_t *check=json_pack("{s:s,s:s,s:s}", - "path",path,"kind","dir","action","read"); + "path",path,"kind",kind,"action","read"); g_free(path); if (!check || json_array_append(checks,check)) { json_decref(check); From f7ee1eeb28c47ca9b66488d95c03cc41c407eaff Mon Sep 17 00:00:00 2001 From: servicememeai Date: Fri, 23 Oct 2026 19:08:02 +0900 Subject: [PATCH 2/3] test(acl): reject treating every directory listing entry as a directory --- tests/test_cf_acl_dirent_kind.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 tests/test_cf_acl_dirent_kind.py diff --git a/tests/test_cf_acl_dirent_kind.py b/tests/test_cf_acl_dirent_kind.py new file mode 100644 index 00000000..123b1583 --- /dev/null +++ b/tests/test_cf_acl_dirent_kind.py @@ -0,0 +1,19 @@ +"""Cheap contract: native batch sends file vs directory kind to Hub Authority.""" +from pathlib import Path +import unittest + + +class NativeDirentKindTests(unittest.TestCase): + def test_native_permission_batch_uses_real_dirent_mode(self): + root = Path(__file__).resolve().parents[1] + source = (root / 'common' / 'cf-acl.c').read_text(encoding='utf-8') + chunk = source.split('filter_chunk (', 1)[1].split('\nGList *\ncf_acl_filter_dirents', 1)[0] + self.assertIn('"mode",&mode', chunk) + self.assertIn('S_ISDIR(mode) ? "dir" : "file"', chunk) + self.assertIn('"path",path,"kind",kind,"action","read"', chunk) + self.assertIn('cf_v2_acl_check_json(seaf,payload,body)', chunk) + self.assertIn('json_array_size(permissions)!=size', chunk) + + +if __name__ == '__main__': + unittest.main() From 70931e169fe4be4f4e353a756bdf25984a70bc67 Mon Sep 17 00:00:00 2001 From: servicememeai Date: Fri, 23 Oct 2026 19:09:45 +0900 Subject: [PATCH 3/3] ci(quick): guard native file/dir kind in permission batches --- .github/workflows/quick.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/quick.yml b/.github/workflows/quick.yml index a86d8d9e..778e0843 100644 --- a/.github/workflows/quick.yml +++ b/.github/workflows/quick.yml @@ -23,6 +23,9 @@ jobs: - name: Block retired managed-library code and contracts run: python3 tests/test_v2_no_managed_library.py + - name: Check native directory/file batch kinds + run: python3 tests/test_cf_acl_dirent_kind.py + - name: Run cheap C-source ACL and Branch retry contracts run: python3 -m unittest discover -s tests -p 'test_cf_*.py'