Skip to content
Open
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
30 changes: 30 additions & 0 deletions .github/workflows/ios-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: iOS CI

on:
pull_request:
push:
branches:
- main
workflow_dispatch:

jobs:
build-and-test:
name: Build and Test (iOS)
runs-on: macos-latest

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Set up Xcode
uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: latest-stable

- name: Build and test
run: |
xcodebuild \
-project ios/awsary.xcodeproj \
-scheme "awsary (iOS)" \
-destination "platform=iOS Simulator,name=iPhone 14" \
clean test
35 changes: 35 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# AGENTS

## Scope
This guidance applies to the entire repository unless a nested `AGENTS.md` overrides it.

## Project overview
This repository contains multiple components (e.g., iOS app, website, Terraform, utilities). Verify which directory you are working in before making changes.

## General workflow
- Favor small, targeted changes that align with existing patterns.
- Run relevant tests or linters for the area you changed when feasible.
- Document any skipped tests and the reason.

## Coding conventions
- Prefer clear, descriptive names consistent with surrounding code.
- Keep formatting consistent with existing files in each subproject.
- Avoid introducing new dependencies without justification.
- Prefer native Swift and SwiftUI with Apple public APIs. Only suggest third-party code when necessary or with significant advantages, and ask a human before adding any external SDK or codebase.

## iOS (Swift/Xcode)
- Follow existing Swift style and naming conventions.
- Use `@MainActor` or concurrency annotations consistently with neighboring code.
- Avoid force-unwrapping unless the codebase already uses it and it is safe.

## Web (website)
- Follow existing linting/formatting rules.
- Keep accessibility in mind (labels, semantics, contrast).

## Infrastructure (terraform)
- Use existing module patterns and naming conventions.
- Keep variables and outputs documented.

## PR/commit notes
- Summarize user-visible changes.
- Call out any migrations, configuration changes, or manual steps.
98 changes: 98 additions & 0 deletions bug_fixes_summary.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
# Bug Fixes Summary

## Overview
This document summarizes the 3 critical bugs identified and fixed in the AWSary codebase, including security vulnerabilities, logic errors, and resource management issues.

## Bug #1: Security Vulnerability in CloudFront Configuration
**Severity:** HIGH
**Type:** Security Vulnerability
**Location:** `terraform/cloudfront_cdn.tf` line 51

### Description
The CloudFront distribution was configured to allow both HTTP and HTTPS traffic (`viewer_protocol_policy = "allow-all"`), which exposes user data to potential interception and violates security best practices.

### Impact
- Sensitive data could be transmitted over unencrypted HTTP connections
- Vulnerability to man-in-the-middle attacks
- Non-compliance with security standards requiring HTTPS

### Fix Applied
Changed `viewer_protocol_policy` from `"allow-all"` to `"redirect-to-https"` to ensure all HTTP traffic is automatically redirected to HTTPS.

```diff
- viewer_protocol_policy = "allow-all"
+ viewer_protocol_policy = "redirect-to-https"
```

## Bug #2: Logic Error in OpenAI Script
**Severity:** MEDIUM
**Type:** Logic Error
**Location:** `utils/open_ai.py` lines 18-19

### Description
The script contained a typo in the key name `shortDesctiption` instead of `shortDescription`, causing the logic to fail when checking if an OpenAI description already exists.

### Impact
- Script would crash or behave unexpectedly when accessing non-existent key
- Logic condition `if "#" not in item['shortDesctiption']` would always fail
- Potential KeyError exceptions
- Inefficient processing of already-processed items

### Fix Applied
1. Fixed the typo: `shortDesctiption` → `shortDescription`
2. Added safe key access using `item.get('shortDescription', '')` to prevent KeyError
3. Fixed typo in print statement: `OpenAIn` → `OpenAI`

```diff
- if "#" not in item['shortDesctiption'] :
- print("Checking OpenAIn for : " + item['name'])
- item['shortDesctiption'] = chat_completion.choices[0].message.content
+ if "#" not in item.get('shortDescription', '') :
+ print("Checking OpenAI for : " + item['name'])
+ item['shortDescription'] = chat_completion.choices[0].message.content
```

## Bug #3: Resource Management Bug in Polly Script
**Severity:** MEDIUM
**Type:** Resource Management / Memory Leak
**Location:** `utils/polly.py` line 14

### Description
The script opened file handles without using proper context management (`with` statement), which could cause resource leaks or file corruption if exceptions occurred.

### Impact
- File handles could remain open if exceptions occur
- Potential resource exhaustion on systems with limited file descriptors
- Risk of file corruption or incomplete writes
- Poor adherence to Python best practices

### Fix Applied
Replaced manual file opening/closing with context manager (`with` statement) to ensure proper resource cleanup.

```diff
- file = open('speech/' + item['name'].replace(' ','_') + '_Brian_' + 'en-GB' + '.mp3', 'wb')
- file.write(response['AudioStream'].read())
- file.close()
+ filename = 'speech/' + item['name'].replace(' ','_') + '_Brian_' + 'en-GB' + '.mp3'
+ with open(filename, 'wb') as file:
+ file.write(response['AudioStream'].read())
```

## Additional Observations
During the codebase review, several other potential improvements were identified:

1. **OpenAI API Version**: The script uses the deprecated `openai.ChatCompletion.create()` API format (pre-v1.0)
2. **API Key Security**: Hardcoded placeholder API key in the code
3. **Error Handling**: Missing try-catch blocks for API calls and file operations
4. **DynamoDB Pagination**: Scripts don't handle pagination for large DynamoDB tables

## Recommendations
1. Implement comprehensive error handling throughout the Python scripts
2. Update OpenAI API calls to use the current v1.0+ format
3. Move API keys to environment variables or secure configuration
4. Add pagination support for DynamoDB scan operations
5. Implement logging for better debugging and monitoring
6. Add input validation for all user-provided data

## Conclusion
The three bugs fixed represent significant improvements to the codebase's security, reliability, and maintainability. The CloudFront security fix is particularly critical as it prevents potential data exposure through unencrypted connections.
1 change: 1 addition & 0 deletions ios/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.sentryclirc
39 changes: 38 additions & 1 deletion ios/AWSary/AWSaryApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,50 @@
//

import SwiftUI
import Sentry

import SwiftData
import RevenueCat

@main
struct awsaryApp: App {

init() {
SentrySDK.start { options in
options.dsn = "https://477881ef4da534dc2a5d623681bb8ff1@o4509860037001216.ingest.de.sentry.io/4509860041982032"

// for DEV
options.debug = true // Enabled debug when first installing is always helpful
options.environment = "dev"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Development Sentry configuration committed for production build

Medium Severity

Sentry SDK is configured with options.debug = true and options.environment = "dev" while production settings are commented out. Additionally, tracesSampleRate and sessionSampleRate are set to 1.0 (100%), which the comments note should be adjusted for production. This configuration will cause verbose debug logging in production builds, report all events as "dev" environment in Sentry dashboards, and incur higher costs from 100% sampling.

Additional Locations (1)

Fix in Cursor Fix in Web


// for PROD
//options.debug = false
//options.environment = "production"

// Adds IP for users.
// For more information, visit: https://docs.sentry.io/platforms/apple/data-management/data-collected/
options.sendDefaultPii = true

// Set tracesSampleRate to 1.0 to capture 100% of transactions for performance monitoring.
// We recommend adjusting this value in production.
options.tracesSampleRate = 1.0

// Configure profiling. Visit https://docs.sentry.io/platforms/apple/profiling/ to learn more.
options.configureProfiling = {
$0.sessionSampleRate = 1.0 // We recommend adjusting this value in production.
$0.lifecycle = .trace
}

// Uncomment the following lines to add more data to your events
// options.attachScreenshot = true // This adds a screenshot to the error events
// options.attachViewHierarchy = true // This adds the view hierarchy to the error events

// Enable experimental logging features
options.experimental.enableLogs = true
}
// Remove the next line after confirming that your Sentry integration is working.
// SentrySDK.capture(message: "This app uses Sentry! :)")

// RevenueCat
Purchases.logLevel = .debug
Purchases.configure(withAPIKey: Constants.apiKey)

Expand Down
41 changes: 30 additions & 11 deletions ios/Shared/MainViews/DetailsView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,20 +38,39 @@ struct DetailsView: View {
AWSserviceImagePlaceHolderView(service: service, showLabel: awsServiceLogoWithLabel)
VStack{
Text(service.longName).font(Font.title)
HStack{
Image("Arch_Amazon-Polly_64")
.resizable()
.scaledToFit()
.frame(width: 40)
.cornerRadius(8.0)
Text("Pronunciation by Amazon Polly").lineLimit(2).font(.caption2)
}.onTapGesture {
playServiceName(url: "https://cdn.awsary.com/audio/\(service.imageURL.replacingOccurrences(of: "https://static.tig.pt/awsary/logos/Arch_", with: "").replacingOccurrences(of: "_64.svg", with: "").replacingOccurrences(of: "Amazon-", with: "").replacingOccurrences(of: "AWS-", with: ""))-Joanna-en-US.mp3")
}
HStack{
ZStack{
RoundedRectangle(cornerRadius: 8)
.foregroundStyle(Color.green)
.frame(width: 40, height: 40)
Image(systemName: "document.on.document")
}
.onTapGesture {
UIPasteboard.general.string = service.shortDesctiption
}
.onDrag({
let itemProvider = NSItemProvider(object: service.shortDesctiption as NSString)
return itemProvider
})

HStack{
Image("Arch_Amazon-Polly_64")
.resizable()
.scaledToFit()
.frame(width: 40)
.cornerRadius(8.0)
Text("Pronunciation by Polly").lineLimit(2).font(.caption2)
}.onTapGesture {
playServiceName(url: "https://cdn.awsary.com/audio/\(service.imageURL.replacingOccurrences(of: "https://static.tig.pt/awsary/logos/Arch_", with: "").replacingOccurrences(of: "_64.svg", with: "").replacingOccurrences(of: "Amazon-", with: "").replacingOccurrences(of: "AWS-", with: ""))-Joanna-en-US.mp3")
}
}
.padding(.leading, 10)
}
}
Spacer()
Markdown(service.shortDesctiption).padding()
Markdown(service.shortDesctiption)
.textSelection(.enabled)
.padding()
Spacer()
HStack{
// VStack(alignment: .leading){
Expand Down
Loading
Loading