feat: initial repo — docs and scripts for Gitea read-only token access
Three-layer access scheme: owner -> reader account -> scoped API token. Includes 6 automation scripts, config template, EN/RU docs, and manual curl guide. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
config.ini
|
||||||
108
README.md
Normal file
108
README.md
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
# gitea-token-access
|
||||||
|
|
||||||
|
Scripts and documentation for setting up restricted read-only access to private Gitea repositories.
|
||||||
|
|
||||||
|
## Problem
|
||||||
|
|
||||||
|
You have private repos on a Gitea server and need to give automated tools (installers, CI/CD, scripts) read access — without exposing your admin credentials.
|
||||||
|
|
||||||
|
## Solution
|
||||||
|
|
||||||
|
A three-layer scheme:
|
||||||
|
|
||||||
|
1. **Owner account** — full admin access, owns all repos
|
||||||
|
2. **Reader account** — restricted "hobo" account with no admin rights, only sees repos where explicitly added as collaborator
|
||||||
|
3. **API token** — scoped to `read:repository`, can only read what the reader account can see
|
||||||
|
|
||||||
|
If the token leaks, revoke it and rotate — no admin credentials are exposed.
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. Copy and fill in your config
|
||||||
|
cp config.example.ini config.ini
|
||||||
|
nano config.ini
|
||||||
|
|
||||||
|
# 2. Create reader account and token
|
||||||
|
bash scripts/setup-reader.sh
|
||||||
|
|
||||||
|
# 3. Grant access to a specific repo
|
||||||
|
bash scripts/grant-access.sh my-private-repo
|
||||||
|
|
||||||
|
# 4. Verify it works
|
||||||
|
bash scripts/test-access.sh my-private-repo
|
||||||
|
```
|
||||||
|
|
||||||
|
## Scripts
|
||||||
|
|
||||||
|
| Script | Description |
|
||||||
|
|--------|-------------|
|
||||||
|
| `setup-reader.sh` | Create reader account + API token |
|
||||||
|
| `grant-access.sh <repo>` | Grant read access to a repo |
|
||||||
|
| `revoke-access.sh <repo>` | Revoke access from a repo |
|
||||||
|
| `list-access.sh` | List all accessible repos |
|
||||||
|
| `rotate-token.sh` | Delete old token, create new one |
|
||||||
|
| `test-access.sh [repo]` | Verify token and access work |
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
Copy `config.example.ini` to `config.ini` and fill in your values:
|
||||||
|
|
||||||
|
```ini
|
||||||
|
[gitea]
|
||||||
|
url = https://git.example.com
|
||||||
|
api_url = https://git.example.com/api/v1
|
||||||
|
|
||||||
|
[owner]
|
||||||
|
username = admin-user
|
||||||
|
password = admin-password
|
||||||
|
|
||||||
|
[reader]
|
||||||
|
username = readonly-user
|
||||||
|
password = reader-password
|
||||||
|
email = reader@noreply.local
|
||||||
|
token_name = installer-readonly
|
||||||
|
token_scope = read:repository
|
||||||
|
```
|
||||||
|
|
||||||
|
The `config.ini` file is gitignored and will never be committed.
|
||||||
|
|
||||||
|
## Using the Token
|
||||||
|
|
||||||
|
### In scripts (curl)
|
||||||
|
```bash
|
||||||
|
curl -H "Authorization: token YOUR_TOKEN" \
|
||||||
|
https://git.example.com/api/v1/repos/owner/repo/raw/file.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
### Git clone
|
||||||
|
```bash
|
||||||
|
git clone https://reader:YOUR_TOKEN@git.example.com/owner/repo.git
|
||||||
|
```
|
||||||
|
|
||||||
|
### Git credential store
|
||||||
|
```bash
|
||||||
|
echo "https://reader:YOUR_TOKEN@git.example.com" >> ~/.git-credentials
|
||||||
|
git config --global credential.helper store
|
||||||
|
git clone https://git.example.com/owner/repo.git
|
||||||
|
```
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
|
||||||
|
- [Architecture](docs/architecture.md) — how the owner/reader/token scheme works
|
||||||
|
- [Manual Setup](docs/manual-setup.md) — step-by-step curl commands
|
||||||
|
- [README (Russian)](README_ru.md)
|
||||||
|
|
||||||
|
## Security Notes
|
||||||
|
|
||||||
|
- The token has `read:repository` scope only — it cannot write, delete, or access admin APIs
|
||||||
|
- Access is per-repo: the reader only sees repos where they are an explicit collaborator
|
||||||
|
- If the token is compromised: run `rotate-token.sh` to invalidate old token and create a new one
|
||||||
|
- `config.ini` contains credentials — it is gitignored and must never be committed
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
- Gitea instance with API enabled
|
||||||
|
- Owner account with admin privileges
|
||||||
|
- `curl` and `bash`
|
||||||
|
- No external dependencies (no jq, python, etc.)
|
||||||
158
README_ru.md
Normal file
158
README_ru.md
Normal file
@@ -0,0 +1,158 @@
|
|||||||
|
# gitea-token-access
|
||||||
|
|
||||||
|
Скрипты и документация для настройки ограниченного read-only доступа к приватным репозиториям Gitea.
|
||||||
|
|
||||||
|
## Зачем это нужно
|
||||||
|
|
||||||
|
Есть приватные репо на Gitea-сервере. Нужно дать автоматическим инструментам (установщики, CI/CD, скрипты) доступ на чтение — без раскрытия админских учётных данных.
|
||||||
|
|
||||||
|
## Схема
|
||||||
|
|
||||||
|
Трёхуровневая модель доступа:
|
||||||
|
|
||||||
|
```
|
||||||
|
Владелец (admin)
|
||||||
|
│
|
||||||
|
├── создаёт "бомж"-аккаунт (через Admin API)
|
||||||
|
├── выдаёт доступ к конкретным репо (collaborator, read)
|
||||||
|
│
|
||||||
|
v
|
||||||
|
Бомж-аккаунт (reader)
|
||||||
|
│
|
||||||
|
├── не имеет админ-прав
|
||||||
|
├── видит только те репо, куда его добавили
|
||||||
|
│
|
||||||
|
v
|
||||||
|
API-токен (scope: read:repository)
|
||||||
|
│
|
||||||
|
├── может только читать
|
||||||
|
├── используется в скриптах/установщиках
|
||||||
|
└── при утечке — ротируем, админ-данные не раскрыты
|
||||||
|
```
|
||||||
|
|
||||||
|
## Быстрый старт
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. Скопировать и заполнить конфиг
|
||||||
|
cp config.example.ini config.ini
|
||||||
|
nano config.ini
|
||||||
|
|
||||||
|
# 2. Создать бомж-аккаунт и токен
|
||||||
|
bash scripts/setup-reader.sh
|
||||||
|
|
||||||
|
# 3. Дать доступ к конкретному репо
|
||||||
|
bash scripts/grant-access.sh my-private-repo
|
||||||
|
|
||||||
|
# 4. Проверить что всё работает
|
||||||
|
bash scripts/test-access.sh my-private-repo
|
||||||
|
```
|
||||||
|
|
||||||
|
## Скрипты
|
||||||
|
|
||||||
|
| Скрипт | Описание |
|
||||||
|
|--------|----------|
|
||||||
|
| `setup-reader.sh` | Создать бомж-аккаунт + API-токен |
|
||||||
|
| `grant-access.sh <repo>` | Выдать доступ на чтение к репо |
|
||||||
|
| `revoke-access.sh <repo>` | Забрать доступ |
|
||||||
|
| `list-access.sh` | Показать все доступные репо |
|
||||||
|
| `rotate-token.sh` | Удалить старый токен, создать новый |
|
||||||
|
| `test-access.sh [repo]` | Проверить что токен и доступ работают |
|
||||||
|
|
||||||
|
## Конфигурация
|
||||||
|
|
||||||
|
Скопируйте `config.example.ini` в `config.ini` и заполните своими данными:
|
||||||
|
|
||||||
|
```ini
|
||||||
|
[gitea]
|
||||||
|
url = https://git.example.com
|
||||||
|
api_url = https://git.example.com/api/v1
|
||||||
|
|
||||||
|
[owner]
|
||||||
|
username = ваш-админ
|
||||||
|
password = ваш-пароль
|
||||||
|
|
||||||
|
[reader]
|
||||||
|
username = reader-аккаунт
|
||||||
|
password = пароль-reader
|
||||||
|
email = reader@noreply.local
|
||||||
|
token_name = installer-readonly
|
||||||
|
token_scope = read:repository
|
||||||
|
```
|
||||||
|
|
||||||
|
Файл `config.ini` добавлен в `.gitignore` и никогда не будет закоммичен.
|
||||||
|
|
||||||
|
## Использование токена
|
||||||
|
|
||||||
|
### В скриптах (curl)
|
||||||
|
```bash
|
||||||
|
curl -H "Authorization: token ВАШ_ТОКЕН" \
|
||||||
|
https://git.example.com/api/v1/repos/owner/repo/raw/file.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
### Git clone
|
||||||
|
```bash
|
||||||
|
git clone https://reader:ВАШ_ТОКЕН@git.example.com/owner/repo.git
|
||||||
|
```
|
||||||
|
|
||||||
|
### Git credential store
|
||||||
|
```bash
|
||||||
|
echo "https://reader:ВАШ_ТОКЕН@git.example.com" >> ~/.git-credentials
|
||||||
|
git config --global credential.helper store
|
||||||
|
git clone https://git.example.com/owner/repo.git
|
||||||
|
```
|
||||||
|
|
||||||
|
## FAQ
|
||||||
|
|
||||||
|
### Что делать если токен утёк?
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bash scripts/rotate-token.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Старый токен будет удалён и перестанет работать. Новый будет записан в `config.ini`. Обновите токен во всех системах, которые его используют.
|
||||||
|
|
||||||
|
### Как дать доступ к новому репо?
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bash scripts/grant-access.sh имя-нового-репо
|
||||||
|
```
|
||||||
|
|
||||||
|
### Как убрать доступ к репо?
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bash scripts/revoke-access.sh имя-репо
|
||||||
|
```
|
||||||
|
|
||||||
|
### Как посмотреть к чему есть доступ?
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bash scripts/list-access.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
### Можно ли использовать для другого Gitea-сервера?
|
||||||
|
|
||||||
|
Да. Просто измените `url` и `api_url` в `config.ini`. Скрипты универсальны и работают с любым Gitea-инстансом.
|
||||||
|
|
||||||
|
### Нужен ли jq или python?
|
||||||
|
|
||||||
|
Нет. Скрипты используют только `bash`, `curl`, `grep`, `sed` — стандартные утилиты Linux.
|
||||||
|
|
||||||
|
## Документация
|
||||||
|
|
||||||
|
- [Архитектура](docs/architecture.md) — схема владелец/бомж/токен
|
||||||
|
- [Ручная настройка](docs/manual-setup.md) — пошаговые curl-команды
|
||||||
|
- [README (English)](README.md)
|
||||||
|
|
||||||
|
## Безопасность
|
||||||
|
|
||||||
|
- Токен имеет scope `read:repository` — не может писать, удалять или использовать админ API
|
||||||
|
- Доступ гранулярный: бомж видит только те репо, где он явно добавлен как collaborator
|
||||||
|
- При компрометации токена: запустите `rotate-token.sh`
|
||||||
|
- `config.ini` содержит учётные данные — он в `.gitignore` и не коммитится
|
||||||
|
|
||||||
|
## Требования
|
||||||
|
|
||||||
|
- Gitea-инстанс с включённым API
|
||||||
|
- Аккаунт владельца с правами администратора
|
||||||
|
- `curl` и `bash`
|
||||||
|
- Никаких внешних зависимостей
|
||||||
18
config.example.ini
Normal file
18
config.example.ini
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
[gitea]
|
||||||
|
url = https://git.example.com
|
||||||
|
api_url = https://git.example.com/api/v1
|
||||||
|
|
||||||
|
[owner]
|
||||||
|
# Admin account that owns the repositories
|
||||||
|
username = myuser
|
||||||
|
password = mypassword
|
||||||
|
|
||||||
|
[reader]
|
||||||
|
# Restricted read-only account
|
||||||
|
username = myreader
|
||||||
|
password = readerpassword
|
||||||
|
email = myreader@noreply.local
|
||||||
|
token_name = installer-readonly
|
||||||
|
token_scope = read:repository
|
||||||
|
# After running setup-reader.sh, the token will be written here:
|
||||||
|
# token = sha1_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||||
68
docs/architecture.md
Normal file
68
docs/architecture.md
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
# Architecture: Read-Only Token Access for Gitea
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
This scheme provides controlled, minimal-privilege access to private Gitea repositories without sharing the owner's credentials.
|
||||||
|
|
||||||
|
## Components
|
||||||
|
|
||||||
|
```
|
||||||
|
+-------------------+
|
||||||
|
| Owner Account | Full admin access to Gitea
|
||||||
|
| (e.g. aibot777) | Owns all repositories
|
||||||
|
+--------+----------+
|
||||||
|
|
|
||||||
|
| Creates & manages via Admin API
|
||||||
|
v
|
||||||
|
+-------------------+
|
||||||
|
| Reader Account | Restricted account ("hobo account")
|
||||||
|
| (e.g. uclaude- | No admin rights
|
||||||
|
| reader) | Can only access repos where explicitly
|
||||||
|
+--------+----------+ added as collaborator (read permission)
|
||||||
|
|
|
||||||
|
| Authenticates via
|
||||||
|
v
|
||||||
|
+-------------------+
|
||||||
|
| API Token | scope: read:repository
|
||||||
|
| (sha1_xxx...) | Can only READ repos the reader
|
||||||
|
+--------+----------+ account has access to
|
||||||
|
|
|
||||||
|
| Used by
|
||||||
|
v
|
||||||
|
+-------------------+
|
||||||
|
| Scripts/Installers| git clone, curl, wget
|
||||||
|
| CI/CD pipelines | Any tool that needs read access
|
||||||
|
+-------------------+
|
||||||
|
```
|
||||||
|
|
||||||
|
## Access Flow
|
||||||
|
|
||||||
|
1. **Owner** creates the reader account (one-time setup)
|
||||||
|
2. **Owner** grants the reader access to specific repos (per-repo)
|
||||||
|
3. **Reader's token** is used by automated tools to read those repos
|
||||||
|
4. If the token leaks — revoke it, rotate, no owner credentials exposed
|
||||||
|
|
||||||
|
## Security Properties
|
||||||
|
|
||||||
|
| Property | Status |
|
||||||
|
|----------|--------|
|
||||||
|
| Owner credentials exposed | No |
|
||||||
|
| Token can write to repos | No (read:repository scope) |
|
||||||
|
| Token can access admin API | No |
|
||||||
|
| Token can access repos not granted | No |
|
||||||
|
| Token can be rotated independently | Yes |
|
||||||
|
| Access is per-repo granular | Yes |
|
||||||
|
|
||||||
|
## Gitea API Endpoints Used
|
||||||
|
|
||||||
|
| Action | Method | Endpoint | Auth |
|
||||||
|
|--------|--------|----------|------|
|
||||||
|
| Create user | POST | `/admin/users` | Owner (admin) |
|
||||||
|
| Activate user | PATCH | `/admin/users/{username}` | Owner (admin) |
|
||||||
|
| Create token | POST | `/users/{username}/tokens` | Reader (basic) |
|
||||||
|
| Delete token | DELETE | `/users/{username}/tokens/{name}` | Reader (basic) |
|
||||||
|
| Add collaborator | PUT | `/repos/{owner}/{repo}/collaborators/{user}` | Owner |
|
||||||
|
| Remove collaborator | DELETE | `/repos/{owner}/{repo}/collaborators/{user}` | Owner |
|
||||||
|
| List repos | GET | `/user/repos` | Reader (token) |
|
||||||
|
| Get repo | GET | `/repos/{owner}/{repo}` | Reader (token) |
|
||||||
|
| Get raw file | GET | `/repos/{owner}/{repo}/raw/{path}` | Reader (token) |
|
||||||
137
docs/manual-setup.md
Normal file
137
docs/manual-setup.md
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
# Manual Setup via curl
|
||||||
|
|
||||||
|
Step-by-step commands for setting up read-only access manually.
|
||||||
|
Replace placeholders with your actual values.
|
||||||
|
|
||||||
|
## Variables
|
||||||
|
|
||||||
|
```bash
|
||||||
|
GITEA_API="https://git.example.com/api/v1"
|
||||||
|
OWNER="myuser"
|
||||||
|
OWNER_PASS="mypassword"
|
||||||
|
READER="myreader"
|
||||||
|
READER_PASS="readerpassword"
|
||||||
|
READER_EMAIL="myreader@noreply.local"
|
||||||
|
```
|
||||||
|
|
||||||
|
## 1. Create Reader Account
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X POST "$GITEA_API/admin/users" \
|
||||||
|
-u "$OWNER:$OWNER_PASS" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{
|
||||||
|
"username": "'"$READER"'",
|
||||||
|
"password": "'"$READER_PASS"'",
|
||||||
|
"email": "'"$READER_EMAIL"'",
|
||||||
|
"must_change_password": false,
|
||||||
|
"visibility": "public"
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected: HTTP 201
|
||||||
|
|
||||||
|
## 2. Activate Account
|
||||||
|
|
||||||
|
Some Gitea configurations require explicit activation:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X PATCH "$GITEA_API/admin/users/$READER" \
|
||||||
|
-u "$OWNER:$OWNER_PASS" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{
|
||||||
|
"active": true,
|
||||||
|
"visibility": "public",
|
||||||
|
"login_name": "'"$READER"'"
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
## 3. Create API Token
|
||||||
|
|
||||||
|
Authenticate as the reader to create a token with limited scope:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X POST "$GITEA_API/users/$READER/tokens" \
|
||||||
|
-u "$READER:$READER_PASS" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{
|
||||||
|
"name": "installer-readonly",
|
||||||
|
"scopes": ["read:repository"]
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
Response:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"name": "installer-readonly",
|
||||||
|
"sha1": "abc123...",
|
||||||
|
"token_last_eight": "abc12345"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Save the `sha1` value — it is only shown once.
|
||||||
|
|
||||||
|
## 4. Grant Access to a Repository
|
||||||
|
|
||||||
|
```bash
|
||||||
|
REPO="my-private-repo"
|
||||||
|
|
||||||
|
curl -X PUT "$GITEA_API/repos/$OWNER/$REPO/collaborators/$READER" \
|
||||||
|
-u "$OWNER:$OWNER_PASS" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{"permission": "read"}'
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected: HTTP 204
|
||||||
|
|
||||||
|
## 5. Verify Access
|
||||||
|
|
||||||
|
With token (should work):
|
||||||
|
```bash
|
||||||
|
TOKEN="abc123..."
|
||||||
|
|
||||||
|
curl -H "Authorization: token $TOKEN" \
|
||||||
|
"$GITEA_API/repos/$OWNER/$REPO"
|
||||||
|
```
|
||||||
|
|
||||||
|
Without token (should return 404 for private repo):
|
||||||
|
```bash
|
||||||
|
curl "$GITEA_API/repos/$OWNER/$REPO"
|
||||||
|
```
|
||||||
|
|
||||||
|
## 6. Clone with Token
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone "https://$READER:$TOKEN@git.example.com/$OWNER/$REPO.git"
|
||||||
|
```
|
||||||
|
|
||||||
|
Or download a specific file:
|
||||||
|
```bash
|
||||||
|
curl -H "Authorization: token $TOKEN" \
|
||||||
|
"$GITEA_API/repos/$OWNER/$REPO/raw/README.md"
|
||||||
|
```
|
||||||
|
|
||||||
|
## 7. Revoke Access
|
||||||
|
|
||||||
|
Remove from collaborators:
|
||||||
|
```bash
|
||||||
|
curl -X DELETE "$GITEA_API/repos/$OWNER/$REPO/collaborators/$READER" \
|
||||||
|
-u "$OWNER:$OWNER_PASS"
|
||||||
|
```
|
||||||
|
|
||||||
|
## 8. Rotate Token
|
||||||
|
|
||||||
|
Delete old:
|
||||||
|
```bash
|
||||||
|
curl -X DELETE "$GITEA_API/users/$READER/tokens/installer-readonly" \
|
||||||
|
-u "$READER:$READER_PASS"
|
||||||
|
```
|
||||||
|
|
||||||
|
Create new:
|
||||||
|
```bash
|
||||||
|
curl -X POST "$GITEA_API/users/$READER/tokens" \
|
||||||
|
-u "$READER:$READER_PASS" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{"name": "installer-readonly", "scopes": ["read:repository"]}'
|
||||||
|
```
|
||||||
85
scripts/grant-access.sh
Executable file
85
scripts/grant-access.sh
Executable file
@@ -0,0 +1,85 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||||
|
CONFIG="${SCRIPT_DIR}/../config.ini"
|
||||||
|
|
||||||
|
if [[ $# -lt 1 ]]; then
|
||||||
|
echo "Usage: $0 <repo-name> [config.ini]"
|
||||||
|
echo "Grant read access to a repository for the reader account."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
REPO="$1"
|
||||||
|
[[ -n "${2:-}" ]] && CONFIG="$2"
|
||||||
|
|
||||||
|
if [[ ! -f "$CONFIG" ]]; then
|
||||||
|
echo "ERROR: config file not found: $CONFIG"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --- Parse INI ---
|
||||||
|
parse_ini() {
|
||||||
|
local file="$1" section="$2" key="$3"
|
||||||
|
sed -n "/^\[$section\]/,/^\[/p" "$file" | grep "^${key}\s*=" | head -1 | sed 's/^[^=]*=\s*//' | sed 's/\s*$//'
|
||||||
|
}
|
||||||
|
|
||||||
|
GITEA_API=$(parse_ini "$CONFIG" gitea api_url)
|
||||||
|
OWNER_USER=$(parse_ini "$CONFIG" owner username)
|
||||||
|
OWNER_PASS=$(parse_ini "$CONFIG" owner password)
|
||||||
|
READER_USER=$(parse_ini "$CONFIG" reader username)
|
||||||
|
READER_PASS=$(parse_ini "$CONFIG" reader password)
|
||||||
|
TOKEN=$(parse_ini "$CONFIG" reader token)
|
||||||
|
|
||||||
|
echo "=== Grant Access: $OWNER_USER/$REPO -> $READER_USER ==="
|
||||||
|
|
||||||
|
# --- Add as collaborator (read permission) ---
|
||||||
|
echo "[1/3] Adding '$READER_USER' as collaborator (read)..."
|
||||||
|
HTTP_CODE=$(curl -s -o /tmp/gitea_grant.json -w "%{http_code}" \
|
||||||
|
-X PUT "$GITEA_API/repos/$OWNER_USER/$REPO/collaborators/$READER_USER" \
|
||||||
|
-u "$OWNER_USER:$OWNER_PASS" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{"permission": "read"}')
|
||||||
|
|
||||||
|
if [[ "$HTTP_CODE" == "204" || "$HTTP_CODE" == "200" ]]; then
|
||||||
|
echo " -> Collaborator added."
|
||||||
|
else
|
||||||
|
echo " -> ERROR: HTTP $HTTP_CODE"
|
||||||
|
cat /tmp/gitea_grant.json
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --- Accept invitation (if required by Gitea) ---
|
||||||
|
echo "[2/3] Accepting collaboration invite (if any)..."
|
||||||
|
# List pending notifications/invitations and accept
|
||||||
|
PENDING=$(curl -s \
|
||||||
|
-u "$READER_USER:$READER_PASS" \
|
||||||
|
"$GITEA_API/user/repos" | grep -c "\"name\":\"$REPO\"" 2>/dev/null || echo "0")
|
||||||
|
|
||||||
|
if [[ "$PENDING" == "0" ]]; then
|
||||||
|
# Try to accept via notifications — some Gitea versions auto-accept
|
||||||
|
echo " -> Auto-accepted or no invite needed."
|
||||||
|
else
|
||||||
|
echo " -> Already accessible."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --- Verify access with token ---
|
||||||
|
echo "[3/3] Verifying access with token..."
|
||||||
|
if [[ -z "$TOKEN" ]]; then
|
||||||
|
echo " -> WARNING: No token in config.ini, skipping verification."
|
||||||
|
echo " -> Run setup-reader.sh first to create a token."
|
||||||
|
else
|
||||||
|
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" \
|
||||||
|
-H "Authorization: token $TOKEN" \
|
||||||
|
"$GITEA_API/repos/$OWNER_USER/$REPO")
|
||||||
|
|
||||||
|
if [[ "$HTTP_CODE" == "200" ]]; then
|
||||||
|
echo " -> Access confirmed (HTTP 200)."
|
||||||
|
else
|
||||||
|
echo " -> WARNING: HTTP $HTTP_CODE — access may not be working yet."
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== Done ==="
|
||||||
|
echo "Repo '$OWNER_USER/$REPO' is now readable by '$READER_USER'."
|
||||||
41
scripts/list-access.sh
Executable file
41
scripts/list-access.sh
Executable file
@@ -0,0 +1,41 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||||
|
CONFIG="${1:-$SCRIPT_DIR/../config.ini}"
|
||||||
|
|
||||||
|
if [[ ! -f "$CONFIG" ]]; then
|
||||||
|
echo "ERROR: config file not found: $CONFIG"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --- Parse INI ---
|
||||||
|
parse_ini() {
|
||||||
|
local file="$1" section="$2" key="$3"
|
||||||
|
sed -n "/^\[$section\]/,/^\[/p" "$file" | grep "^${key}\s*=" | head -1 | sed 's/^[^=]*=\s*//' | sed 's/\s*$//'
|
||||||
|
}
|
||||||
|
|
||||||
|
GITEA_API=$(parse_ini "$CONFIG" gitea api_url)
|
||||||
|
READER_USER=$(parse_ini "$CONFIG" reader username)
|
||||||
|
TOKEN=$(parse_ini "$CONFIG" reader token)
|
||||||
|
|
||||||
|
if [[ -z "$TOKEN" ]]; then
|
||||||
|
echo "ERROR: No token found in config.ini. Run setup-reader.sh first."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "=== Repositories accessible by '$READER_USER' ==="
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
REPOS=$(curl -s \
|
||||||
|
-H "Authorization: token $TOKEN" \
|
||||||
|
"$GITEA_API/user/repos?limit=50")
|
||||||
|
|
||||||
|
# Parse JSON with grep/sed (no jq dependency)
|
||||||
|
echo "$REPOS" | grep -o '"full_name":"[^"]*"' | sed 's/"full_name":"//;s/"//' | while read -r repo; do
|
||||||
|
echo " - $repo"
|
||||||
|
done
|
||||||
|
|
||||||
|
COUNT=$(echo "$REPOS" | grep -o '"full_name":"[^"]*"' | wc -l)
|
||||||
|
echo ""
|
||||||
|
echo "Total: $COUNT repositories"
|
||||||
45
scripts/revoke-access.sh
Executable file
45
scripts/revoke-access.sh
Executable file
@@ -0,0 +1,45 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||||
|
CONFIG="${SCRIPT_DIR}/../config.ini"
|
||||||
|
|
||||||
|
if [[ $# -lt 1 ]]; then
|
||||||
|
echo "Usage: $0 <repo-name> [config.ini]"
|
||||||
|
echo "Revoke reader access from a repository."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
REPO="$1"
|
||||||
|
[[ -n "${2:-}" ]] && CONFIG="$2"
|
||||||
|
|
||||||
|
if [[ ! -f "$CONFIG" ]]; then
|
||||||
|
echo "ERROR: config file not found: $CONFIG"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --- Parse INI ---
|
||||||
|
parse_ini() {
|
||||||
|
local file="$1" section="$2" key="$3"
|
||||||
|
sed -n "/^\[$section\]/,/^\[/p" "$file" | grep "^${key}\s*=" | head -1 | sed 's/^[^=]*=\s*//' | sed 's/\s*$//'
|
||||||
|
}
|
||||||
|
|
||||||
|
GITEA_API=$(parse_ini "$CONFIG" gitea api_url)
|
||||||
|
OWNER_USER=$(parse_ini "$CONFIG" owner username)
|
||||||
|
OWNER_PASS=$(parse_ini "$CONFIG" owner password)
|
||||||
|
READER_USER=$(parse_ini "$CONFIG" reader username)
|
||||||
|
|
||||||
|
echo "=== Revoke Access: $OWNER_USER/$REPO -> $READER_USER ==="
|
||||||
|
|
||||||
|
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" \
|
||||||
|
-X DELETE "$GITEA_API/repos/$OWNER_USER/$REPO/collaborators/$READER_USER" \
|
||||||
|
-u "$OWNER_USER:$OWNER_PASS")
|
||||||
|
|
||||||
|
if [[ "$HTTP_CODE" == "204" || "$HTTP_CODE" == "200" ]]; then
|
||||||
|
echo "-> Access revoked successfully."
|
||||||
|
elif [[ "$HTTP_CODE" == "404" ]]; then
|
||||||
|
echo "-> User was not a collaborator (404)."
|
||||||
|
else
|
||||||
|
echo "-> ERROR: HTTP $HTTP_CODE"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
76
scripts/rotate-token.sh
Executable file
76
scripts/rotate-token.sh
Executable file
@@ -0,0 +1,76 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||||
|
CONFIG="${1:-$SCRIPT_DIR/../config.ini}"
|
||||||
|
|
||||||
|
if [[ ! -f "$CONFIG" ]]; then
|
||||||
|
echo "ERROR: config file not found: $CONFIG"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --- Parse INI ---
|
||||||
|
parse_ini() {
|
||||||
|
local file="$1" section="$2" key="$3"
|
||||||
|
sed -n "/^\[$section\]/,/^\[/p" "$file" | grep "^${key}\s*=" | head -1 | sed 's/^[^=]*=\s*//' | sed 's/\s*$//'
|
||||||
|
}
|
||||||
|
|
||||||
|
GITEA_API=$(parse_ini "$CONFIG" gitea api_url)
|
||||||
|
READER_USER=$(parse_ini "$CONFIG" reader username)
|
||||||
|
READER_PASS=$(parse_ini "$CONFIG" reader password)
|
||||||
|
TOKEN_NAME=$(parse_ini "$CONFIG" reader token_name)
|
||||||
|
TOKEN_SCOPE=$(parse_ini "$CONFIG" reader token_scope)
|
||||||
|
|
||||||
|
TOKEN_NAME="${TOKEN_NAME:-installer-readonly}"
|
||||||
|
TOKEN_SCOPE="${TOKEN_SCOPE:-read:repository}"
|
||||||
|
|
||||||
|
echo "=== Token Rotation for '$READER_USER' ==="
|
||||||
|
|
||||||
|
# --- Delete old token ---
|
||||||
|
echo "[1/2] Deleting old token '$TOKEN_NAME'..."
|
||||||
|
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" \
|
||||||
|
-X DELETE "$GITEA_API/users/$READER_USER/tokens/$TOKEN_NAME" \
|
||||||
|
-u "$READER_USER:$READER_PASS")
|
||||||
|
|
||||||
|
if [[ "$HTTP_CODE" == "204" || "$HTTP_CODE" == "200" ]]; then
|
||||||
|
echo " -> Old token deleted."
|
||||||
|
elif [[ "$HTTP_CODE" == "404" ]]; then
|
||||||
|
echo " -> No existing token found (404), creating fresh."
|
||||||
|
else
|
||||||
|
echo " -> WARNING: HTTP $HTTP_CODE while deleting old token."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --- Create new token ---
|
||||||
|
echo "[2/2] Creating new token '$TOKEN_NAME' (scope: $TOKEN_SCOPE)..."
|
||||||
|
TOKEN_RESPONSE=$(curl -s \
|
||||||
|
-X POST "$GITEA_API/users/$READER_USER/tokens" \
|
||||||
|
-u "$READER_USER:$READER_PASS" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d "{\"name\": \"$TOKEN_NAME\", \"scopes\": [\"$TOKEN_SCOPE\"]}")
|
||||||
|
|
||||||
|
TOKEN_VALUE=$(echo "$TOKEN_RESPONSE" | grep -o '"sha1":"[^"]*"' | sed 's/"sha1":"//;s/"//')
|
||||||
|
|
||||||
|
if [[ -z "$TOKEN_VALUE" ]]; then
|
||||||
|
echo " -> ERROR: Failed to create new token:"
|
||||||
|
echo "$TOKEN_RESPONSE"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo " -> New token: ${TOKEN_VALUE:0:8}..."
|
||||||
|
|
||||||
|
# --- Update config.ini ---
|
||||||
|
if grep -q "^token\s*=" "$CONFIG" 2>/dev/null; then
|
||||||
|
sed -i "s|^token\s*=.*|token = $TOKEN_VALUE|" "$CONFIG"
|
||||||
|
echo " -> Token updated in $CONFIG"
|
||||||
|
else
|
||||||
|
sed -i "/^\[reader\]/,/^\[/{
|
||||||
|
/^token_scope/a token = $TOKEN_VALUE
|
||||||
|
}" "$CONFIG"
|
||||||
|
echo " -> Token added to $CONFIG"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== Rotation Complete ==="
|
||||||
|
echo "New token (first 8): ${TOKEN_VALUE:0:8}..."
|
||||||
|
echo ""
|
||||||
|
echo "IMPORTANT: Update any systems using the old token!"
|
||||||
120
scripts/setup-reader.sh
Executable file
120
scripts/setup-reader.sh
Executable file
@@ -0,0 +1,120 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||||
|
CONFIG="${1:-$SCRIPT_DIR/../config.ini}"
|
||||||
|
|
||||||
|
if [[ ! -f "$CONFIG" ]]; then
|
||||||
|
echo "ERROR: config file not found: $CONFIG"
|
||||||
|
echo "Usage: $0 [path/to/config.ini]"
|
||||||
|
echo "Copy config.example.ini to config.ini and fill in your values."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --- Parse INI ---
|
||||||
|
parse_ini() {
|
||||||
|
local file="$1" section="$2" key="$3"
|
||||||
|
sed -n "/^\[$section\]/,/^\[/p" "$file" | grep "^${key}\s*=" | head -1 | sed 's/^[^=]*=\s*//' | sed 's/\s*$//'
|
||||||
|
}
|
||||||
|
|
||||||
|
GITEA_API=$(parse_ini "$CONFIG" gitea api_url)
|
||||||
|
OWNER_USER=$(parse_ini "$CONFIG" owner username)
|
||||||
|
OWNER_PASS=$(parse_ini "$CONFIG" owner password)
|
||||||
|
READER_USER=$(parse_ini "$CONFIG" reader username)
|
||||||
|
READER_PASS=$(parse_ini "$CONFIG" reader password)
|
||||||
|
READER_EMAIL=$(parse_ini "$CONFIG" reader email)
|
||||||
|
TOKEN_NAME=$(parse_ini "$CONFIG" reader token_name)
|
||||||
|
TOKEN_SCOPE=$(parse_ini "$CONFIG" reader token_scope)
|
||||||
|
|
||||||
|
if [[ -z "$GITEA_API" || -z "$OWNER_USER" || -z "$OWNER_PASS" || -z "$READER_USER" || -z "$READER_PASS" ]]; then
|
||||||
|
echo "ERROR: missing required fields in config.ini"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
READER_EMAIL="${READER_EMAIL:-${READER_USER}@noreply.local}"
|
||||||
|
TOKEN_NAME="${TOKEN_NAME:-installer-readonly}"
|
||||||
|
TOKEN_SCOPE="${TOKEN_SCOPE:-read:repository}"
|
||||||
|
|
||||||
|
echo "=== Gitea Reader Account Setup ==="
|
||||||
|
echo "Server: $GITEA_API"
|
||||||
|
echo "Owner: $OWNER_USER"
|
||||||
|
echo "Reader: $READER_USER"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# --- Step 1: Create reader account ---
|
||||||
|
echo "[1/4] Creating reader account '$READER_USER'..."
|
||||||
|
HTTP_CODE=$(curl -s -o /tmp/gitea_create_user.json -w "%{http_code}" \
|
||||||
|
-X POST "$GITEA_API/admin/users" \
|
||||||
|
-u "$OWNER_USER:$OWNER_PASS" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d "{
|
||||||
|
\"username\": \"$READER_USER\",
|
||||||
|
\"password\": \"$READER_PASS\",
|
||||||
|
\"email\": \"$READER_EMAIL\",
|
||||||
|
\"must_change_password\": false,
|
||||||
|
\"visibility\": \"public\"
|
||||||
|
}")
|
||||||
|
|
||||||
|
if [[ "$HTTP_CODE" == "201" ]]; then
|
||||||
|
echo " -> Account created."
|
||||||
|
elif [[ "$HTTP_CODE" == "422" ]]; then
|
||||||
|
echo " -> Account already exists (422), continuing."
|
||||||
|
else
|
||||||
|
echo " -> ERROR: HTTP $HTTP_CODE"
|
||||||
|
cat /tmp/gitea_create_user.json
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --- Step 2: Activate account ---
|
||||||
|
echo "[2/4] Activating account and setting visibility..."
|
||||||
|
curl -s -o /dev/null -w "" \
|
||||||
|
-X PATCH "$GITEA_API/admin/users/$READER_USER" \
|
||||||
|
-u "$OWNER_USER:$OWNER_PASS" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{"active": true, "visibility": "public", "login_name": "'"$READER_USER"'"}'
|
||||||
|
echo " -> Done."
|
||||||
|
|
||||||
|
# --- Step 3: Delete existing token with same name (if any) ---
|
||||||
|
echo "[3/4] Cleaning up old tokens..."
|
||||||
|
curl -s -o /dev/null -w "" \
|
||||||
|
-X DELETE "$GITEA_API/users/$READER_USER/tokens/$TOKEN_NAME" \
|
||||||
|
-u "$READER_USER:$READER_PASS" 2>/dev/null || true
|
||||||
|
echo " -> Done."
|
||||||
|
|
||||||
|
# --- Step 4: Create API token ---
|
||||||
|
echo "[4/4] Creating API token '$TOKEN_NAME' (scope: $TOKEN_SCOPE)..."
|
||||||
|
TOKEN_RESPONSE=$(curl -s \
|
||||||
|
-X POST "$GITEA_API/users/$READER_USER/tokens" \
|
||||||
|
-u "$READER_USER:$READER_PASS" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d "{\"name\": \"$TOKEN_NAME\", \"scopes\": [\"$TOKEN_SCOPE\"]}")
|
||||||
|
|
||||||
|
TOKEN_VALUE=$(echo "$TOKEN_RESPONSE" | grep -o '"sha1":"[^"]*"' | sed 's/"sha1":"//;s/"//')
|
||||||
|
|
||||||
|
if [[ -z "$TOKEN_VALUE" ]]; then
|
||||||
|
echo " -> ERROR: Failed to extract token from response:"
|
||||||
|
echo "$TOKEN_RESPONSE"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo " -> Token created: ${TOKEN_VALUE:0:8}..."
|
||||||
|
|
||||||
|
# --- Write token back to config.ini ---
|
||||||
|
if grep -q "^token\s*=" "$CONFIG" 2>/dev/null; then
|
||||||
|
sed -i "s|^token\s*=.*|token = $TOKEN_VALUE|" "$CONFIG"
|
||||||
|
else
|
||||||
|
# Add token under [reader] section
|
||||||
|
sed -i "/^\[reader\]/,/^\[/{
|
||||||
|
/^token_scope/a token = $TOKEN_VALUE
|
||||||
|
}" "$CONFIG"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== Setup Complete ==="
|
||||||
|
echo "Reader account: $READER_USER"
|
||||||
|
echo "Token (first 8): ${TOKEN_VALUE:0:8}..."
|
||||||
|
echo "Token written to: $CONFIG"
|
||||||
|
echo ""
|
||||||
|
echo "Next steps:"
|
||||||
|
echo " bash scripts/grant-access.sh <repo-name>"
|
||||||
|
echo " bash scripts/test-access.sh <repo-name>"
|
||||||
93
scripts/test-access.sh
Executable file
93
scripts/test-access.sh
Executable file
@@ -0,0 +1,93 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||||
|
CONFIG="${SCRIPT_DIR}/../config.ini"
|
||||||
|
|
||||||
|
REPO="${1:-}"
|
||||||
|
[[ -n "${2:-}" ]] && CONFIG="$2"
|
||||||
|
|
||||||
|
if [[ ! -f "$CONFIG" ]]; then
|
||||||
|
echo "ERROR: config file not found: $CONFIG"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --- Parse INI ---
|
||||||
|
parse_ini() {
|
||||||
|
local file="$1" section="$2" key="$3"
|
||||||
|
sed -n "/^\[$section\]/,/^\[/p" "$file" | grep "^${key}\s*=" | head -1 | sed 's/^[^=]*=\s*//' | sed 's/\s*$//'
|
||||||
|
}
|
||||||
|
|
||||||
|
GITEA_URL=$(parse_ini "$CONFIG" gitea url)
|
||||||
|
GITEA_API=$(parse_ini "$CONFIG" gitea api_url)
|
||||||
|
OWNER_USER=$(parse_ini "$CONFIG" owner username)
|
||||||
|
READER_USER=$(parse_ini "$CONFIG" reader username)
|
||||||
|
TOKEN=$(parse_ini "$CONFIG" reader token)
|
||||||
|
|
||||||
|
if [[ -z "$TOKEN" ]]; then
|
||||||
|
echo "ERROR: No token found in config.ini. Run setup-reader.sh first."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
PASS=0
|
||||||
|
FAIL=0
|
||||||
|
|
||||||
|
check() {
|
||||||
|
local desc="$1" expected="$2" actual="$3"
|
||||||
|
if [[ "$actual" == "$expected" ]]; then
|
||||||
|
echo " PASS: $desc (HTTP $actual)"
|
||||||
|
((PASS++))
|
||||||
|
else
|
||||||
|
echo " FAIL: $desc (expected $expected, got $actual)"
|
||||||
|
((FAIL++))
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "=== Access Test for '$READER_USER' ==="
|
||||||
|
echo "Server: $GITEA_API"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# --- Test 1: Token is valid (list repos) ---
|
||||||
|
echo "[Test 1] Token validity — list repos..."
|
||||||
|
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" \
|
||||||
|
-H "Authorization: token $TOKEN" \
|
||||||
|
"$GITEA_API/user/repos")
|
||||||
|
check "GET /user/repos with token" "200" "$HTTP_CODE"
|
||||||
|
|
||||||
|
# --- Test 2: Token scope limitation (should NOT access admin endpoints) ---
|
||||||
|
echo "[Test 2] Token scope — admin API should be denied..."
|
||||||
|
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" \
|
||||||
|
-H "Authorization: token $TOKEN" \
|
||||||
|
"$GITEA_API/admin/users")
|
||||||
|
check "GET /admin/users with read-only token" "403" "$HTTP_CODE"
|
||||||
|
|
||||||
|
if [[ -n "$REPO" ]]; then
|
||||||
|
echo ""
|
||||||
|
echo "[Test 3] Repo access — $OWNER_USER/$REPO..."
|
||||||
|
|
||||||
|
# --- Test 3a: Access with token ---
|
||||||
|
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" \
|
||||||
|
-H "Authorization: token $TOKEN" \
|
||||||
|
"$GITEA_API/repos/$OWNER_USER/$REPO")
|
||||||
|
check "GET /repos/$OWNER_USER/$REPO with token" "200" "$HTTP_CODE"
|
||||||
|
|
||||||
|
# --- Test 3b: Access without token (private repo should be 404) ---
|
||||||
|
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" \
|
||||||
|
"$GITEA_API/repos/$OWNER_USER/$REPO")
|
||||||
|
check "GET /repos/$OWNER_USER/$REPO without token (expect 404)" "404" "$HTTP_CODE"
|
||||||
|
|
||||||
|
# --- Test 3c: Clone URL with token ---
|
||||||
|
echo ""
|
||||||
|
echo "[Info] Clone URL for scripts/installers:"
|
||||||
|
echo " git clone https://${READER_USER}:${TOKEN}@${GITEA_URL#https://}/${OWNER_USER}/${REPO}.git"
|
||||||
|
echo " (or use: Authorization: token $TOKEN header)"
|
||||||
|
else
|
||||||
|
echo ""
|
||||||
|
echo "[Info] Pass a repo name to test specific repo access:"
|
||||||
|
echo " $0 <repo-name>"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== Results: $PASS passed, $FAIL failed ==="
|
||||||
|
[[ "$FAIL" -gt 0 ]] && exit 1
|
||||||
|
exit 0
|
||||||
Reference in New Issue
Block a user