diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..671b8dc --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,15 @@ +{ + "name": "DevTunnel Feature Test", + "image": "mcr.microsoft.com/devcontainers/base:ubuntu", + "features": { + "./src/devtunnel": { + "version": "latest" + } + }, + "customizations": { + "vscode": { + "extensions": [] + } + }, + "postCreateCommand": "devtunnel --version" +} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..52cb3f0 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,52 @@ +name: "CI - Test DevContainer Features" +on: + pull_request: + paths: + - 'src/**' + push: + branches: + - main + paths: + - 'src/**' + +jobs: + validate: + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - uses: actions/checkout@v4 + + - name: "Validate JSON files" + run: | + for file in $(find src -name "*.json"); do + echo "Validating $file" + python3 -m json.tool "$file" > /dev/null + done + + - name: "Validate shell scripts" + run: | + for file in $(find src -name "*.sh"); do + echo "Validating $file" + bash -n "$file" + done + + test: + runs-on: ubuntu-latest + permissions: + contents: read + strategy: + matrix: + features: + - devtunnel + steps: + - uses: actions/checkout@v4 + + - name: "Install DevContainer CLI" + run: npm install -g @devcontainers/cli + + - name: "Test feature: ${{ matrix.features }}" + run: | + devcontainer features test \ + --base-image mcr.microsoft.com/devcontainers/base:ubuntu \ + --features ${{ matrix.features }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..82ca41b --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,26 @@ +name: "Release DevContainer Features" +on: + workflow_dispatch: + push: + branches: + - main + paths: + - 'src/**' + +jobs: + release: + runs-on: ubuntu-latest + permissions: + contents: write + packages: write + steps: + - uses: actions/checkout@v4 + + - name: "Publish Features" + uses: devcontainers/action@v1 + with: + publish-features: "true" + base-path-to-features: "./src" + generate-docs: "true" + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..79d1595 --- /dev/null +++ b/.gitignore @@ -0,0 +1,20 @@ +# Build artifacts +*.log +.DS_Store + +# Node modules if testing +node_modules/ +npm-debug.log* + +# Test artifacts +test/ + +# Editor directories +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# OS files +Thumbs.db diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..5bdc9a0 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,130 @@ +# Contributing to DevTunnel DevContainer Feature + +Thank you for your interest in contributing to this project! This document provides guidelines and information for contributors. + +## How to Contribute + +1. **Fork the repository** and create a new branch for your feature or bugfix +2. **Make your changes** following the guidelines below +3. **Test your changes** using a devcontainer +4. **Submit a pull request** with a clear description of your changes + +## Development Setup + +### Testing the Feature Locally + +You can test this feature locally by: + +1. Clone this repository +2. Open it in VS Code with the Dev Containers extension installed +3. The `.devcontainer/devcontainer.json` is configured to use the local feature +4. Rebuild the container to test your changes + +### Testing in Another Project + +To test the feature in another project before publishing: + +```json +{ + "image": "mcr.microsoft.com/devcontainers/base:ubuntu", + "features": { + "ghcr.io/abeckDev/devtunnel-devcontainer-feature/devtunnel:1": { + "version": "latest" + } + } +} +``` + +## Feature Structure + +The feature follows the [DevContainer Features specification](https://containers.dev/implementors/features/): + +``` +src/devtunnel/ +├── devcontainer-feature.json # Feature metadata and options +├── install.sh # Installation script +├── README.md # Auto-generated documentation +└── NOTES.md # Additional notes +``` + +### devcontainer-feature.json + +This file contains: +- Feature ID, name, and version +- Description +- Options (configuration parameters) +- VS Code customizations (extensions, settings) + +### install.sh + +The installation script must: +- Run as root +- Be idempotent (safe to run multiple times) +- Support multiple architectures (amd64, arm64) +- Handle errors gracefully +- Use `set -e` for error handling +- Clean up temporary files + +### README.md + +The README is primarily auto-generated from `devcontainer-feature.json`. Additional notes should go in `NOTES.md`. + +## Code Style + +### Shell Script Guidelines + +- Use `#!/usr/bin/env bash` shebang +- Enable strict mode with `set -e` +- Use meaningful variable names in UPPER_CASE +- Include comments for complex logic +- Check for required dependencies +- Validate architecture support + +### JSON Guidelines + +- Use 2-space indentation +- Follow the DevContainer Features schema +- Validate JSON with a linter before committing + +## Version Numbering + +This project follows [Semantic Versioning](https://semver.org/): + +- **MAJOR**: Breaking changes +- **MINOR**: New features (backward compatible) +- **PATCH**: Bug fixes (backward compatible) + +## Publishing Process + +Features are published to GitHub Container Registry (GHCR) via GitHub Actions when: + +1. Changes are merged to the main branch +2. A new tag is created +3. The automated workflow builds and publishes the feature + +## Testing Checklist + +Before submitting a PR, ensure: + +- [ ] Shell script passes `bash -n` syntax check +- [ ] JSON files are valid (`python3 -m json.tool`) +- [ ] Feature installs successfully in a devcontainer +- [ ] Feature works on both amd64 and arm64 (if possible to test) +- [ ] Documentation is updated +- [ ] Version number is incremented appropriately + +## Resources + +- [DevContainer Features Specification](https://containers.dev/implementors/features/) +- [DevContainer Features Template](https://github.com/devcontainers/feature-starter) +- [Official Features Repository](https://github.com/devcontainers/features) +- [DevTunnel Documentation](https://learn.microsoft.com/en-us/azure/developer/dev-tunnels/) + +## Questions? + +If you have questions, please: +1. Check the [documentation](./README.md) +2. Search [existing issues](https://github.com/abeckDev/devtunnel-devcontainer-feature/issues) +3. Open a new issue if needed + +Thank you for contributing! 🎉 diff --git a/README.md b/README.md index 8ba6a81..37d16d5 100644 --- a/README.md +++ b/README.md @@ -1 +1,95 @@ -# devtunnel-devcontainer-feature \ No newline at end of file +# DevTunnel DevContainer Feature + +A [DevContainer Feature](https://containers.dev/implementors/features/) for installing the Microsoft DevTunnel CLI. + +## Features + +This repository contains the following DevContainer feature: + +- **devtunnel**: Installs the Microsoft DevTunnel CLI for creating secure tunnels to localhost. + +## What is DevTunnel? + +DevTunnel is a Microsoft service that creates secure, ad-hoc connections from the internet to your local development environment. It allows you to: + +- **Test Webhooks**: Receive webhook callbacks from external services (GitHub, Stripe, etc.) +- **Share Development Work**: Give team members or clients access to your local application +- **Test on Remote Devices**: Access your local server from mobile devices or other machines +- **Collaborate Remotely**: Share your development environment without complex network configuration + +## Usage + +To use this feature in your devcontainer, add it to your `devcontainer.json`: + +```json +{ + "image": "mcr.microsoft.com/devcontainers/base:ubuntu", + "features": { + "ghcr.io/abeckDev/devtunnel-devcontainer-feature/devtunnel:1": {} + } +} +``` + +### With Options + +```json +{ + "image": "mcr.microsoft.com/devcontainers/base:ubuntu", + "features": { + "ghcr.io/abeckDev/devtunnel-devcontainer-feature/devtunnel:1": { + "version": "latest" + } + } +} +``` + +## Quick Start + +Once the feature is installed in your devcontainer: + +1. **Login to DevTunnel**: + ```bash + devtunnel user login + ``` + +2. **Host a tunnel** (e.g., for a service running on port 3000): + ```bash + devtunnel host -p 3000 + ``` + +3. **Allow anonymous access** (optional): + ```bash + devtunnel host -p 3000 --allow-anonymous + ``` + +## Examples + +Check out the [examples](./examples) directory for sample devcontainer configurations: +- [Basic Example](./examples/basic) - Simple setup with DevTunnel CLI + +## Documentation + +For detailed documentation, see: +- [Feature Documentation](./src/devtunnel/README.md) +- [Microsoft DevTunnel Overview](https://learn.microsoft.com/en-us/azure/developer/dev-tunnels/overview) +- [DevTunnel CLI Commands](https://learn.microsoft.com/en-us/azure/developer/dev-tunnels/cli-commands) + +## Supported Platforms + +- **OS**: Debian/Ubuntu-based Linux distributions +- **Architectures**: + - amd64 (x86_64) + - arm64 (aarch64) + +## Contributing + +Contributions are welcome! Please feel free to submit a Pull Request. + +## License + +This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. + +## Acknowledgments + +- Based on the [DevContainer Features](https://github.com/devcontainers/features) specification +- Microsoft DevTunnel CLI: [Dev Tunnels Documentation](https://learn.microsoft.com/en-us/azure/developer/dev-tunnels/) \ No newline at end of file diff --git a/examples/basic/.devcontainer.json b/examples/basic/.devcontainer.json new file mode 100644 index 0000000..496f89c --- /dev/null +++ b/examples/basic/.devcontainer.json @@ -0,0 +1,10 @@ +{ + "name": "DevTunnel Basic Example", + "image": "mcr.microsoft.com/devcontainers/base:ubuntu", + "features": { + "ghcr.io/abeckDev/devtunnel-devcontainer-feature/devtunnel:1": { + "version": "latest" + } + }, + "postCreateCommand": "echo 'DevTunnel CLI installed! Run: devtunnel user login' && devtunnel --version" +} diff --git a/examples/basic/README.md b/examples/basic/README.md new file mode 100644 index 0000000..2ec21e7 --- /dev/null +++ b/examples/basic/README.md @@ -0,0 +1,54 @@ +# Basic DevTunnel Example + +This is a basic example showing how to use the DevTunnel DevContainer Feature. + +## What's Included + +This devcontainer configuration includes: +- Ubuntu base image +- DevTunnel CLI (latest version) +- Post-create command that verifies installation + +## How to Use + +1. **Open this directory in VS Code** with the Dev Containers extension installed +2. **Reopen in Container** when prompted +3. **Login to DevTunnel**: + ```bash + devtunnel user login + ``` +4. **Start a simple web server** (example with Python): + ```bash + python3 -m http.server 8000 + ``` +5. **Create a tunnel** to share it: + ```bash + devtunnel host -p 8000 --allow-anonymous + ``` + +## Example Commands + +### List all tunnels +```bash +devtunnel list +``` + +### Create a named tunnel +```bash +devtunnel create -a +``` + +### Connect to an existing tunnel +```bash +devtunnel host -p 8000 +``` + +### Delete a tunnel +```bash +devtunnel delete +``` + +## Learn More + +- [DevTunnel Documentation](https://learn.microsoft.com/en-us/azure/developer/dev-tunnels/) +- [DevTunnel CLI Commands](https://learn.microsoft.com/en-us/azure/developer/dev-tunnels/cli-commands) diff --git a/src/devtunnel/NOTES.md b/src/devtunnel/NOTES.md new file mode 100644 index 0000000..bf2aa16 --- /dev/null +++ b/src/devtunnel/NOTES.md @@ -0,0 +1,37 @@ + +## Version Support + +Currently, only the `latest` version is supported because Microsoft provides DevTunnel CLI downloads through aka.ms redirect URLs that always point to the latest version. There is no official versioned release system available at this time. + +## OS Support + +This feature should work on recent versions of Debian/Ubuntu-based distributions with the `apt` package manager installed. + +Supported architectures: +- `amd64` (x86_64) - Downloads from https://aka.ms/TunnelsCliDownload/linux-x64 +- `arm64` (aarch64) - Downloads from https://aka.ms/TunnelsCliDownload/linux-arm64 + +`bash` is required to execute the `install.sh` script. + +## Authentication + +DevTunnel requires authentication before use. Users must run `devtunnel user login` to authenticate with either: +- Microsoft Account +- GitHub Account + +This authentication step cannot be automated in the installation script as it requires interactive user login. + +## Security Considerations + +DevTunnel creates publicly accessible URLs to your local services. Always: +- Use authentication when sharing sensitive applications +- Use `--allow-anonymous` only when necessary +- Be aware of what services you're exposing to the internet +- Review DevTunnel's [security documentation](https://learn.microsoft.com/en-us/azure/developer/dev-tunnels/security) + +## Links + +- [DevTunnel Overview](https://learn.microsoft.com/en-us/azure/developer/dev-tunnels/overview) +- [CLI Command Reference](https://learn.microsoft.com/en-us/azure/developer/dev-tunnels/cli-commands) +- [Get Started Guide](https://learn.microsoft.com/en-us/azure/developer/dev-tunnels/get-started) +- [FAQ](https://learn.microsoft.com/en-us/azure/developer/dev-tunnels/faq) diff --git a/src/devtunnel/README.md b/src/devtunnel/README.md new file mode 100644 index 0000000..146e811 --- /dev/null +++ b/src/devtunnel/README.md @@ -0,0 +1,92 @@ + +# DevTunnel CLI (devtunnel) + +Installs the Microsoft DevTunnel CLI for creating secure tunnels to localhost. This is useful for sharing local web services for development, testing, and debugging from virtually anywhere. + +DevTunnel enables you to securely expose your local development server to the internet, making it accessible for testing webhooks, sharing work with team members, or testing on remote devices. + +## Example Usage + +```json +"features": { + "ghcr.io/abeckDev/devtunnel-devcontainer-feature/devtunnel:1": {} +} +``` + +## Options + +| Options Id | Description | Type | Default Value | +|-----|-----|-----|-----| +| version | Select or enter a DevTunnel CLI version. Use 'latest' for the most recent version. | string | latest | + +## Usage Examples + +After installing this feature, you can use the `devtunnel` CLI in your dev container: + +### Login + +First, authenticate with a Microsoft or GitHub account: + +```bash +devtunnel user login +``` + +### Create and Host a Tunnel + +Host a tunnel for your local development server (e.g., running on port 3000): + +```bash +devtunnel host -p 3000 +``` + +### Allow Anonymous Access + +For sharing with external users without authentication: + +```bash +devtunnel host -p 3000 --allow-anonymous +``` + +### List All Tunnels + +View all your active tunnels: + +```bash +devtunnel list +``` + +### Get Help + +View all available commands and options: + +```bash +devtunnel --help +``` + +## About DevTunnel + +DevTunnel is a Microsoft service that creates secure, ad-hoc connections from the internet to your local development environment. It's particularly useful for: + +- **Webhook Development**: Test webhooks from services like GitHub, Stripe, or Twilio +- **Remote Testing**: Share your local app with team members or clients +- **Mobile Development**: Test web apps on physical mobile devices +- **IoT Development**: Connect to devices that need to communicate with your local services + +For more information, visit: +- [DevTunnel Overview](https://learn.microsoft.com/en-us/azure/developer/dev-tunnels/overview) +- [DevTunnel CLI Commands](https://learn.microsoft.com/en-us/azure/developer/dev-tunnels/cli-commands) +- [Get Started Guide](https://learn.microsoft.com/en-us/azure/developer/dev-tunnels/get-started) + +## OS Support + +This feature should work on recent versions of Debian/Ubuntu-based distributions with the `apt` package manager installed. + +Supported architectures: +- `amd64` (x86_64) +- `arm64` (aarch64) + +`bash` is required to execute the `install.sh` script. + +--- + +_Note: This file was auto-generated from the [devcontainer-feature.json](https://github.com/abeckDev/devtunnel-devcontainer-feature/blob/main/src/devtunnel/devcontainer-feature.json). Add additional notes to a `NOTES.md`._ diff --git a/src/devtunnel/devcontainer-feature.json b/src/devtunnel/devcontainer-feature.json new file mode 100644 index 0000000..d627dfa --- /dev/null +++ b/src/devtunnel/devcontainer-feature.json @@ -0,0 +1,22 @@ +{ + "id": "devtunnel", + "version": "1.0.0", + "name": "DevTunnel CLI", + "documentationURL": "https://github.com/abeckDev/devtunnel-devcontainer-feature", + "description": "Installs the Microsoft DevTunnel CLI for creating secure tunnels to localhost. Useful for sharing local services for development and testing.", + "options": { + "version": { + "type": "string", + "proposals": [ + "latest" + ], + "default": "latest", + "description": "Select or enter a DevTunnel CLI version. Use 'latest' for the most recent version." + } + }, + "customizations": { + "vscode": { + "extensions": [] + } + } +} diff --git a/src/devtunnel/install.sh b/src/devtunnel/install.sh new file mode 100755 index 0000000..c7b834b --- /dev/null +++ b/src/devtunnel/install.sh @@ -0,0 +1,110 @@ +#!/usr/bin/env bash +#------------------------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information. +#------------------------------------------------------------------------------------------------------------- +# +# Docs: https://github.com/abeckDev/devtunnel-devcontainer-feature +# Maintainer: abeckDev +# +# Syntax: ./install.sh [version] + +set -e + +DEVTUNNEL_VERSION="${VERSION:-"latest"}" + +if [ "$(id -u)" -ne 0 ]; then + echo -e 'Script must be run as root. Use sudo, su, or add "USER root" to your Dockerfile before running this script.' + exit 1 +fi + +# Clean up +rm -rf /var/lib/apt/lists/* + +# Ensure dependencies are installed +apt_get_update() +{ + if [ "$(find /var/lib/apt/lists/* | wc -l)" = "0" ]; then + echo "Running apt-get update..." + apt-get update -y + fi +} + +# Checks if packages are installed and installs them if not +check_packages() { + if ! dpkg -s "$@" > /dev/null 2>&1; then + apt_get_update + apt-get -y install --no-install-recommends "$@" + fi +} + +export DEBIAN_FRONTEND=noninteractive + +# Install dependencies +echo "(*) Installing dependencies..." +check_packages curl ca-certificates + +# Determine architecture +architecture="$(dpkg --print-architecture)" + +case "${architecture}" in + amd64) + DEVTUNNEL_ARCH="linux-x64" + ;; + arm64) + DEVTUNNEL_ARCH="linux-arm64" + ;; + *) + echo "(!) Architecture ${architecture} is not supported." + exit 1 + ;; +esac + +echo "(*) Downloading DevTunnel CLI for ${DEVTUNNEL_ARCH}..." + +# Download DevTunnel CLI +if [ "${DEVTUNNEL_VERSION}" = "latest" ]; then + DOWNLOAD_URL="https://aka.ms/TunnelsCliDownload/${DEVTUNNEL_ARCH}" +else + echo "(!) Only 'latest' version is currently supported. Microsoft does not provide versioned download URLs." + echo " Using latest version..." + DOWNLOAD_URL="https://aka.ms/TunnelsCliDownload/${DEVTUNNEL_ARCH}" +fi + +# Download and install +echo "(*) Downloading from ${DOWNLOAD_URL}..." +# Try up to 3 times to download +max_retries=3 +retry_count=0 +while [ $retry_count -lt $max_retries ]; do + if curl -fsSL "${DOWNLOAD_URL}" -o /usr/local/bin/devtunnel; then + break + else + retry_count=$((retry_count + 1)) + if [ $retry_count -lt $max_retries ]; then + echo "(*) Download failed, retrying ($retry_count/$max_retries)..." + sleep 2 + else + echo "(!) Failed to download DevTunnel CLI after $max_retries attempts" + exit 1 + fi + fi +done + +# Make executable +echo "(*) Making devtunnel executable..." +chmod +x /usr/local/bin/devtunnel + +# Verify installation +if devtunnel --version > /dev/null 2>&1; then + echo "(*) DevTunnel CLI installed successfully!" + devtunnel --version +else + echo "(!) Failed to verify DevTunnel CLI installation" + exit 1 +fi + +# Clean up +rm -rf /var/lib/apt/lists/* + +echo "Done!"