Redmine 的 Repository Controls plugin

每個 SVN 檔案庫都可以透過 conf/authz 去控制哪些人可以讀寫哪些路徑的檔案,
一般來說如果有在用 Trac 或 Redmine 這類 web front-end 的都會希望能在 web UI 上控制,
不會還想要進到 shell 下做修改,
Redmine 的 Repository Controls plugin 就是在做這件事,
不過它的控制方法有點微妙的不同,
不像之前設 Trac 的時候是直接讓 Trac 指向那個 authz 檔做修改,
而是直接掛 Perl module 去讀 Redmine db 裡的設定來控制存取權,
只是這有一個麻煩之處就是沒辦法直接用 SVN 內建的機制,
寫那個 Perl module 的人要重新實作那個功能一遍。

掛上了這個 plugin 之後我首先遇到的問題就是 apache-worker 跑不動它,
一啟動 httpd 就直接 crash 掉了,
查了一陣子發現是那個 Perl module 為了不要讓 LDAP 驗證的動作在每次存取時都重新做一次,
於是造了一份 APR::Table 去 cache 住認證的資訊來加速,
而產生一份 APR::Table 需要傳入一個 APR::Pool 物件,
原作者在 httpd 啟動的時候就做了這個動作並把它們分別存在變數內,
之後要做認證的時候就能去用那一份 APR::Table 去做 cache;
我是不曉得 apache-worker 的原理是怎樣,
反正試來試去就發現 APR::Pool->new 這行只要在載入 httpd 的時候就做一定會炸,
至於炸在哪裡是相當隨機的狀況 (視 httpd.conf 的那一串 LoadModule 寫了什麼而定),
不過這種問題在跑 prefork 版的 Apache 是不會出現就是了,
後來我把 APR::Pool 和 APR::Table 的初始化時間點往後挪到做認證的地方,
這個問題就解決了;
就算是沒有打算要用這個 plugin 去控制檔案存取權限,
只是想使用官方提供的 extra/svn/Redmine.pm 這個 module 做帳號登入控制等基本功能的,
也是會遇上一樣的問題,
這種時候也是把初始化的時間點往後挪就可以。

好不容易讓這個 plugin 可以在 apache-worker 上跑了之後,
我又發現似乎原作者對 Redmine 的 roles 設定以及 SVN 的 authz 設計有些誤解,
Redmine 的 roles 設定畫面裡確實是可以把各種 role 的位置做上下調整,
而這個 plugin 的作者似乎認為那個位置會影響到檔案存取權限的大小,
在程式碼裡對那個部分做了多餘的解讀;
再來又發現它的那個 Perl module 抓 project id 跟 request path 的方法也有問題,
像是我習慣開一個 virtual host 把檔案庫直接放在 / 下面的話他就會判斷錯誤,
這個部分我也做了一點小小的改寫,
不過我不是很熟 Perl 所以也不清楚有沒有什麼更有效率的方法去解就是了,
反正我就是用 split 把 / 當 delimiter 把路徑分解成 array 再慢慢玩,
實際 checkout 過一次之後感覺執行的速度也還不差就是了。

為了能確實控制 non-member 跟 anonymous 的存取權,
我把這 plugin 的 app/views/repository_controls/_form.html.erb 第一行做了點小修改,
變成:

這讓 Repository Controls 設定頁裡的選單可以選擇 Anonymous 和 Non Member 這兩個 roles,
最後就是去修改那個 Perl module 讓它能 work 的跟之前 Trac + authz 的模式一樣了;
不管是這個 plugin 還是 Redmine 官方 release 出來的那個 extra/svn/Redmine.pm,
似乎都會拿 project 的 is_public 屬性來判斷檔案庫是否能被 anonymous 讀取,
我是覺得 web front-end 上的存取限制最好還是跟檔案庫分開,
所以把它拔掉了。

改完以後檔案是長這樣:

至於有沒有問題用一陣子就知道了,
想拿去用的我可要先說這不提供保固,
畢竟 perl 並不是我的專長,
不過跟原版比的話出現 500 Internal Server Error 的機率是大大降低了許多,
至於會不會有恐怖的 memory leakage 我就不清楚了;
特別要注意的地方就是這個版本是給 sqlite 用的,
要給 MySQL 用的話 boolean value 判斷式那邊要改一下。

不過說起保固
這讓我想起了 Firefox 最經典的 about:config 開頭畫面:

這絕對不是翻譯的錯,
它的英文也是差不多的意思,
只是中文翻譯翻得比較生動了些。


2009-12-19 Update
這篇跟 code 有關的東西已經大幅更新過了,
也全面修改成 MySQL 可以用的版本,
詳情請參考:
Redmine 的 Repository Controls plugin (續)