Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
__pycache__/
*.py[cod]
*$py.class
.pytest_cache/
.coverage
htmlcov/
.venv/
venv/
ENV/
.env
.chelon/certs/
*.tar.gz
15 changes: 10 additions & 5 deletions chelon.spec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Name: chelon
Version: 1.0.0
Release: 2%{?dist}
Release: 3%{?dist}
Summary: Remote GPG package signing service

License: GPL-2.0-or-later
Expand Down Expand Up @@ -82,8 +82,7 @@ install -m 644 server/audit.py %{buildroot}%{_datadir}/%{name}/server/
install -m 755 tools/chelon-admin %{buildroot}%{_bindir}/

# Install client tools
install -m 755 tools/chelon-sign-rpm %{buildroot}%{_bindir}/
install -m 755 tools/chelon-sign-repomd %{buildroot}%{_bindir}/
install -m 755 tools/chelon-sign %{buildroot}%{_bindir}/
install -m 644 tools/chelon_client.py %{buildroot}%{_datadir}/%{name}/client/

# Install systemd unit
Expand Down Expand Up @@ -133,11 +132,17 @@ fi

%files client
%doc README.md
%{_bindir}/chelon-sign-rpm
%{_bindir}/chelon-sign-repomd
%{_bindir}/chelon-sign
%{_datadir}/%{name}/client/

%changelog
* Wed Jan 07 2026 Atomicorp <support@atomicorp.com> - 1.0.0-3
- Consolidate chelon-sign-rpm and chelon-sign-repomd into chelon-sign
- Security: Sanitize script paths in RPM macros
- Security: Optimize DoS protection with chunked reading
- Fix: Add error handling for malformed base64 signatures
- Fix: Improve client certificate fallback logic

* Wed Jan 07 2026 Atomicorp <support@atomicorp.com> - 1.0.0-2
- Split into server and client subpackages
- Add client signing tools (chelon-sign-rpm, chelon-sign-repomd)
Expand Down
41 changes: 24 additions & 17 deletions docs/USAGE.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,19 @@ scp /etc/chelon/certs/chelon_ca.crt ~/.chelon/certs/
### Sign an RPM

```bash
# Sign a single RPM
chelon-sign-rpm package.rpm
# Sign a single RPM (detached signature)
chelon-sign package.rpm

# Embed signature into RPM header (Integrated Signing)
# This allows 'rpm -K' to work natively
chelon-sign --resign package.rpm

# Specify key type
chelon-sign-rpm --key-type legacy package.rpm
chelon-sign --key-type legacy package.rpm

# Sign multiple RPMs
for rpm in *.rpm; do
chelon-sign-rpm "$rpm"
chelon-sign "$rpm"
done
```

Expand All @@ -71,11 +75,14 @@ Signature saved to: /tmp/tmp.xyz123
### Sign Repository Metadata

```bash
# Sign repomd.xml
chelon-sign-repomd repodata/repomd.xml
# Sign repomd.xml (auto-detects type)
chelon-sign repodata/repomd.xml

# Explicitly specify type
chelon-sign --type repodata repodata/repomd.xml

# Specify key type
chelon-sign-repomd --key-type modern repodata/repomd.xml
chelon-sign --key-type modern repodata/repomd.xml
```

**Output:**
Expand Down Expand Up @@ -222,11 +229,11 @@ sign_packages:

# Sign all RPMs
- for rpm in dist/*.rpm; do
chelon-sign-rpm "$rpm"
chelon-sign "$rpm"
done

# Sign repository metadata
- chelon-sign-repomd dist/repodata/repomd.xml
- chelon-sign dist/repodata/repomd.xml
```

### Makefile Example
Expand All @@ -237,10 +244,10 @@ RPMS := $(wildcard dist/*.rpm)
sign: $(RPMS)
@for rpm in $(RPMS); do \
echo "Signing $$rpm..."; \
chelon-sign-rpm $$rpm || exit 1; \
chelon-sign $$rpm || exit 1; \
done
@echo "Signing repository metadata..."
@chelon-sign-repomd dist/repodata/repomd.xml
@chelon-sign dist/repodata/repomd.xml

.PHONY: sign
```
Expand All @@ -257,13 +264,13 @@ CHELON_TOKEN="${CHELON_TOKEN:?CHELON_TOKEN not set}"
# Sign all RPMs in directory
for rpm in "$1"/*.rpm; do
echo "Signing: $rpm"
chelon-sign-rpm "$rpm"
chelon-sign "$rpm"
done

# Sign repository metadata
if [ -f "$1/repodata/repomd.xml" ]; then
echo "Signing repository metadata"
chelon-sign-repomd "$1/repodata/repomd.xml"
chelon-sign "$1/repodata/repomd.xml"
fi

echo "All packages signed successfully"
Expand Down Expand Up @@ -308,10 +315,10 @@ curl -k https://gamera:5050/api/v1/keys

```bash
# Modern key (default)
chelon-sign-rpm package.rpm
chelon-sign package.rpm

# Legacy key (explicit)
chelon-sign-rpm --key-type legacy package.rpm
chelon-sign --key-type legacy package.rpm
```

---
Expand Down Expand Up @@ -418,15 +425,15 @@ sudo firewall-cmd --list-all | grep 5050
# Sign all RPMs in parallel (careful with rate limits)

find dist/ -name "*.rpm" | \
xargs -P 4 -I {} chelon-sign-rpm {}
xargs -P 4 -I {} chelon-sign {}
```

### Conditional Signing

```bash
# Only sign if not already signed
if ! rpm -K package.rpm | grep -q "pgp"; then
chelon-sign-rpm package.rpm
chelon-sign package.rpm
fi
```

Expand Down
Binary file removed server/__pycache__/audit.cpython-314.pyc
Binary file not shown.
Binary file removed server/__pycache__/auth.cpython-314.pyc
Binary file not shown.
Binary file removed server/__pycache__/chelon-service.cpython-314.pyc
Binary file not shown.
Binary file removed server/__pycache__/signing_engine.cpython-314.pyc
Binary file not shown.
11 changes: 9 additions & 2 deletions server/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,9 +151,16 @@ def validate_token(self, token: str) -> Dict:

token_id, secret = token.split(':', 1)

# Check if token exists
# Check if token exists, reload if not found (to handle new tokens without restart)
if token_id not in self.tokens:
raise ValueError(f"Unknown token: {token_id}")
with self._lock:
# Double-check inside lock
if token_id not in self.tokens:
logger.info(f"Token {token_id} not found in memory, reloading from {self.tokens_file}")
self.tokens = self._load_tokens()
# After reloading, immediately check if the token now exists
if token_id not in self.tokens:
raise ValueError(f"Unknown token after reload: {token_id}")

token_info = self.tokens[token_id]

Expand Down
21 changes: 14 additions & 7 deletions server/chelon-service.py
Original file line number Diff line number Diff line change
Expand Up @@ -357,16 +357,23 @@ def sign_repodata():

if __name__ == '__main__':
# Run the Flask app
host = os.environ.get('CHELON_HOST', '127.0.0.1')
port = int(os.environ.get('CHELON_PORT', 5050))
# Prioritize config file over environment variables
host = config.get('CHELON_HOST') or os.environ.get('CHELON_HOST', '127.0.0.1')
port = int(config.get('CHELON_PORT') or os.environ.get('CHELON_PORT') or 5050)

logger.info(f"Starting Chelon service on {host}:{port}")

# SSL/TLS Configuration
ssl_cert = os.environ.get('CHELON_SSL_CERT')
ssl_key = os.environ.get('CHELON_SSL_KEY')
ssl_ca = os.environ.get('CHELON_SSL_CA')
verify_client = os.environ.get('CHELON_VERIFY_CLIENT', 'false').lower() == 'true'
# SSL/TLS Configuration - Prefer config file, fall back to environment
ssl_cert = config.get('CHELON_SSL_CERT') or os.environ.get('CHELON_SSL_CERT')
ssl_key = config.get('CHELON_SSL_KEY') or os.environ.get('CHELON_SSL_KEY')
ssl_ca = config.get('CHELON_SSL_CA') or os.environ.get('CHELON_SSL_CA')
Comment thread
atomicturtle marked this conversation as resolved.

# Support both names for backward compatibility/consistency
# Precedence: config['CHELON_SSL_VERIFY_CLIENT'] > config['CHELON_VERIFY_CLIENT'] > env['CHELON_VERIFY_CLIENT']
verify_client_val = (config.get('CHELON_SSL_VERIFY_CLIENT') or
config.get('CHELON_VERIFY_CLIENT') or
os.environ.get('CHELON_VERIFY_CLIENT', 'false'))
verify_client = str(verify_client_val).lower() == 'true'

ssl_context = None
if ssl_cert and ssl_key:
Expand Down
Binary file removed tools/__pycache__/chelon_client.cpython-314.pyc
Binary file not shown.
Loading